方法重载和多态

时间:2009-07-28 19:17:32

标签: c# .net polymorphism overloading dispatch

我正在编写一个.NET Web应用程序,管理员可以在其中自定义呈现给用户的各种数据输入表单。管理员可以创建和自定义大约六种不同的字段类型(即文本,数字,下拉列表,文件上载)。所有字段共享一组基本属性/行为(是否需要该字段?它是否具有默认字段值?)。还有一系列字段特定的属性/行为(即下拉列表具有数据源属性,但文本字段不具有)。为简单起见,我将遗漏问题域的许多其他特征。

类层次结构很简单:一个抽象的超类,它封装了常见的行为/属性,以及大约六个处理字段特定内容的具体子类。

每个字段类型都呈现(即映射到)作为特定类型的.NET服务器控件,所有这些都派生自System.Web.UI.Control。

我创建了以下代码来映射字段域对象及其相应的UI控件之间的值:

public static void Bind(Control control, IList<DocumentFieldBase> fieldBaseList)

     foreach (DocumentFieldBase fieldBase in fields){

            if (typeof (DocumentFieldText).IsInstanceOfType(fieldBase)){
                TextBox textbox = (TextBox) control;
                textbox.Text = (fieldBase as DocumentFieldText).GetValue();
            }

            if (typeof (DocumentFieldDropDown).IsInstanceOfType(fieldBase)){
                DropDown dropDown= (DropDown) control;
                dropDown.Text = (fieldBase as DocumentFieldSelectOne).GetValue().Text;
                dropDown.DataSource= (fieldBase as  DocumentFieldSelectOne).DataSource;
                dropDown.Id= (fieldBase as DocumentFieldSelectOne).GetValue().Id;
            }

            //more if statements left out for brevity
      }
}

如果执行类型检查的语句,我想抛弃那些不敬虔的人。我正在拍摄的方法是使用子类输入为每个字段/控件组合创建一个方法重载。例如:

public static void Bind(TextBox control, DocumentFieldText fieldText){
 //some implementation code
}
public static void Bind(DropDown control, DocumentFieldDropDown fieldDropDown){
 //some implementation code
}  

我希望我可以依靠.NET使用正在使用的特定子类在运行时调用适当的重载:例如:

foreach (DocumentFieldBase field in fields){
  Control control = FindControl(field.Identifier);
  Bind(control, field)
}

不幸的是,当我尝试这个时,编译器会窒息:    参数'1':无法从'System.Web.UI.Control'转换为'TextBox'。

如果我必须将第一个参数强制转换为TextBox,我会回到自己进行类型检查并且无法完成本练习的全部目的。

我正在努力实现a)可能和b)一个好主意?

3 个答案:

答案 0 :(得分:6)

在C#4之前,所有重载都在编译时完成。你必须使用双重调度或访问者模式在执行时有效地超载,并且很快就会变得混乱。

在C#4中,您可以将变量声明为动态变量,并在执行时将其全部排序:

foreach (DocumentFieldBase field in fields){
  dynamic control = FindControl(field.Identifier);
  Bind(control, field)
}

显然目前没什么帮助(除非你使用的是VS2010b1)。

一种选择是使用从TypeAction<object>的映射,但随后会出现继承问题......(您可能必须继续处理从具体类型到类型层次结构的问题对象,直到你在地图中找到一个条目)。您还需要在操作中强制转换为正确的类型:(

答案 1 :(得分:5)

这个问题上的“dispatch”标签非常合适:你想要的是“多次发送”。 C#(与大多数主流语言一样)仅支持“单一调度”,其中要执行的方法仅在您调用方法的对象的(运行时)类型上选择,而不是在其参数的(运行时)类型上选择。 / p>

访客模式通常可用于解决此问题。这个想法是你给DocumentFieldBase一个方法(你在具体的子类中覆盖),它调用Control上的一个方法(在具体的子类中也被覆盖)来完成实际的工作。

不幸的是,Control类的源代码可能不在您的控制之下* ...因此您将不得不求助于更为严厉的解决方案。 this question接受的答案提供了一个使用反射的答案。

*扩展方法只是静态方法的语法糖,因此在编译时解析,在这种情况下无用。

答案 2 :(得分:0)

你不能在DocumentFieldBase中有一个抽象的,非静态的Bind()方法,然后在每个具体类的实现中进行向下转换吗?每个DocumentFieldBase类都知道它正在获取什么类型的Control,不是吗?