通过扩展方法进行多态性?

我有一个类库,其中包含一些基类和从中派生的其他基类。 在这个类库中,我正在利用多态来做我想做的事情。 现在在一个消费应用程序中,我想根据子类的运行时类型更改某些代码的行为。 假设如下:

public class Base { } public class Child1 : Base { } public class Child2 : Base { } 

现在在消费应用程序中,我想做一些如下操作(请注意,以下所有类都在使用应用程序中,并且不能在类库中引用):

 public interface IMyInterface1 { } public interface IMyInterface2 { } public static class Extensions { public static void DoSomething(this Base myObj, Object dependency) { } public static void DoSomething(this Child1 myObj, Object dependency) { IMyInterface1 myInterface = dependency as IMyInterface1; if (myInterface != null) { //Do some Child1 specific logic here } } public static void DoSomething(this Child2 myObj, Object dependency) { IMyInterface2 myInterface = dependency as IMyInterface2; if (myInterface != null) { //Do some Child2 specific logic here } } } 

更新:

这不起作用。 它总是调用基类的扩展方法。 是否有其他方法可以让我这样做,并避免必须显式检查运行时类型? 原因是因为可以添加从Base派生的更多类,并且相应的扩展方法可以来自其他一些外部程序集。

提前致谢。

正如@SLaks已经声明你不能将该方法称为扩展方法(即使使用dynamic类型)…但是你可以用dynamic类型调用静态方法

所以,虽然这会失败

 Base base1 = new Child1(); (base1 as dynamic).DoSomething(); 

这会奏效

 Base base1 = new Child1(); Extensions.DoSomething(base1 as dynamic); 

不,那不行。

使用与重载解析相同的机制静态分派扩展方法。

如果您有编译时类型Base的变量,则无论运行时类型如何,编译器都将始终调用基本扩展方法。

相反,您可以使基本扩展方法检查运行时类型并调用适当的其他扩展方法。

我刚才正在寻找同样的事情。

您可以向扩展类添加一个方法,如下所示:

 public static void DoSomething(this Base myObj, Object dependency) { if(myObj.IsSubclassOf(Base)) { // A derived class, call appropriate extension method. DoSomething(myObj as dynamic, dependency); } else { // The object is Base class so handle it. } } 

如果基类是抽象的(或从不在野外使用),则不需要if / else检查:

 public static void DoSomething(this Base myObj, Object dependency) { DoSomething(myObj as dynamic, dependency); } 

[编辑]实际上这不适用于您的情况,因为您没有实现对所有派生对象的支持(因此仍然可以获得无限递归)。 我想你可以传递一些东西来检查递归,但给出的答案是最简单的。 我会把它留在这里因为它可能引发更多的想法。

下面是显示如何使用扩展方法模拟多态性的最小示例。

 void Main() { var elements = new Base[]{ new Base(){ Name = "Base instance"}, new D1(){ Name = "D1 instance"}, new D2(){ Name = "D2 instance"}, new D3(){ Name = "D3 instance"} }; foreach(Base x in elements){ x.Process(); } } public class Base{ public string Name; } public class D1 : Base {} public class D2 : Base {} public class D3 : Base {} public static class Exts{ public static void Process(this Base obj){ if(obj.GetType() == typeof(Base)) Process(obj); //prevent infinite recursion for Base instances else Process((dynamic) obj); } private static void Process(this T obj) where T: Base { Console.WriteLine("Base/Default: {0}", obj.Name); } public static void Process(this D1 obj){ Console.WriteLine("D1: {0}", obj.Name); } public static void Process(this D2 obj){ Console.WriteLine("D2: {0}", obj.Name); } } 

输出:

  Base/Default: Base instance D1: D1 instance D2: D2 instance Base/Default: D3 instance 

如果您不能使用关键字“dynamic”(旧版.NET),则可以使用reflection来实现相同的function。

取代:

 Base base1 = new Child1(); Extensions.DoSomething(base1 as dynamic); 

你可以写 :

 Base base1 = new Child1(); MethodInfo method = typeof(Extensions).GetMethod("DoSomething", new System.Type[] { base1.GetType() }); if (method) { method.Invoke(new object[] { base1 }); } 
  • Array.Length与Array.Count
  • 绑定转换器作为内部类?
  • 以C-BinaryReader.ReadString的7位格式编码整数
  • Office附加function区:带有2个插件的相同选项卡
  • Registry.GetValue有什么问题?
  • 按照加载巨大XML文件的进度
  • 内存堆安全性:字符串垃圾收集
  • 在C#中实现生产者/消费者模式
  • 升级应用程序时安装到相同路径
  • Castle Windsor:强制解析器使用指定的构造函数
  • 如何在C#中为多个请求保持单个SQL Server连接实例打开?