2009-07-11 179 views
1

请看下面的情况。我有一个XML文档如下,动态铸造C#

<Form> 
    <Control Type="Text" Name="FirstName" /> 
    <Control Type="DateTime" Name="DateOfBirth" /> 
    <Control Type="Text" Name="PlaceOfBirth" /> 
</Form> 

我有一个称为控制与单个抽象方法被称为过程需要的HttpRequest的单个参数的抽象类。我还有两个派生自Control的类,称为TextControl和DateTimeControl。 Text和DateTime都会覆盖Process方法以提供它们自己的实现。

我也有一个Form类,它有一个Process方法接受一个HttpRequest类型的参数,一个构造函数接受一个XmlDocument类型的参数。

创建Form的新实例,并通过XmlDocument参数传入上述Xml(我们如何从字符串获取到XmlDocument是无关紧要的)。然后,我调用刚刚创建的Form I实例的Process方法,并按预期方式传入类型为HttpRequest的参数。

目前为止都很好。现在回到这个问题上。

为了使控件的处理可扩展,我希望能够将类映射为控件类型。

例如。

Form.RegisterControl("Text", Text) 
Form.RegisterControl("DateTime", DateTimeControl) 

在形式的过程方法我想itterate在文档中的每个控制节点(如何做,这是再次不相关)和实例化,其基于注册的类相匹配的类型的类的一个实例通过我们的RegisterControl方法。我可以在这个阶段指定它们来自Control,但不能明确指定它们的类型。因为它们都是从Control派生的,所以我想调用我知道将实现的Process方法。

这甚至可能吗?如果是这样,我会怎么做呢?

回答

4

(这个答案是在某些方面两个不同的答案,这取决于你的问题的意思。希望其中的一个一部分是有帮助的,反正:)


也许最好的办法是通过在一个参数中可以用来在正确的时间创建新的控件。如果您使用C#3,这很简单,只要:

Form.RegisterControl("Text",() => new Text()) 

或者,你可以把一个通用的方法有两个限制:一个,作为一个控制,以及一个用于具有参数的构造函数。

public void RegisterControl<T>(string name) where T : Control, new() 

然后调用它:

Form.RegisterControl<Text>("Text"); 
Form.RegisterControl<DateTimeControl>("DateTime"); 

RegisterControl必须记住它使用任何存储typeof(T),但至少它可能是有理由相信Activator.CreateInstance(Type)将工作以后 - 和你” d有编译时检查。我个人喜欢第一种形式的灵活性 - 如果你传递一个委托,它可以选择使用单例,或者可能是一些内部甚至私有构造函数(取决于它从哪里调用)。你也可以使用一个委托历时适当的数据,太:

Form.RegisterControl("Text", data => new Text(data)); 

你不能表达那种构造与通用约束,这将是比较硬反正以后调用。


编辑:这可能是我自己和Mehrdad误解了这个问题。根据控制类型,你是否有不同的过载RegisterControl?如果是这样,那么在执行时直接调用正确的过载的唯一方法是使用反射或在C#4中使用动态类型。

另一种替代方法是使用双派遣 - 在控件本身中放置一个方法知道如何使用表单注册自己。这将在接口或基类中指定,但在具体子类中覆盖。所以,你的代码是目前:

Form.RegisterControl("Text", control); 

将成为:

control.RegisterWith(Form, "Text"); 

然后可以调用没有问题正确的过载。

基本上你需要记住,重载解析是在编译时执行的,但重载解析是在执行时执行的 - 所以如果你想使某些动态变为动态,请尝试使用多态来处理它。

+0

谢谢乔恩!第一个答案应该是正确的(你假设正确)。我现在正在破解它! – 2009-07-11 23:14:56