我有一个类库,其中包含一些基类和从中派生的其他基类。在这个类库中,我正在利用多态来做我想做的事情。现在在一个消费应用程序中,我想根据子类的运行时类型更改某些代码的行为。假设如下:
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
type)...但是你可以用一个调用静态方法 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<Base>(obj); //prevent infinite recursion for Base instances
else Process((dynamic) obj);
}
private static void Process<T>(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),则可以使用反射来实现相同的功能。
取代:
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 });
}