【发布时间】:2015-06-04 13:42:33
【问题描述】:
更新
请求重新打开,因为其他 SO 答案没有解决方案,但问题的其中一个 cmet 有一个我想接受的解决方案,因为它适用于该场景。
原始问题
我在使用非抽象基类和选择适当扩展方法的子类编写扩展方法时遇到问题。
我在下面有一个非常简单的示例(从一个更大的项目中提取),它使用了扩展方法“Run”。预期的输出列在每个类旁边的注释中。
public class Parent { }; // Should output "Parent"
public class ChildA : Parent { }; // Should output "Child A"
public class ChildB : Parent { }; // Should output "Parent"
// Expected Output: ChildA, Parent, Parent
public class Program
{
public static void Main()
{
var commands = new List<Parent>() { new ChildA(), new ChildB(), new Parent() };
Console.WriteLine(string.Join(", ", commands.Select(c => c.Run())));
}
}
到目前为止,这是我的尝试,但必须有一种更清洁的方法来做到这一点:
- 无类型检查 - 导致 Parent 扩展方法被独占使用(Parent、Parent、Parent)
- 显式类型检查 - 正确的输出,但必须显式检查每个扩展可能性的类型(ChildA、Parent、Parent)
- 尝试将 Convert.ChangeType 转换为动态类型 - 运行时异常,因为扩展无法捕获动态类型(无输出)
- 尝试使用反射进行泛型强制转换 - 尚未完全可操作,但不确定方法是否有效
尝试列表
public static class Extensions
{
public static string Run(this ChildA model)
{
return "ChildA";
}
public static string Run(this Parent model)
{
return model.Run1(); // Change to test different approaches
}
public static string Run1(this Parent model) // No type-checking
{
return "Parent";
}
public static string Run2(this Parent model) // Explicitly check sub-types
{
if (model is ChildA)
return ((ChildA)model).Run();
else
return "Parent";
}
public static string Run3(this Parent model) // Attempted dynamic type conversion
{
if (model.GetType().BaseType == typeof(Parent))
{
dynamic changedObj = Convert.ChangeType(model, model.GetType());
return changedObj.Run();
}
else
return "Parent";
}
public static string Run4(this Parent model) // Attempted reflected generic type conversion
{
if (model.GetType().BaseType == typeof(Parent))
{
var method = typeof(Extensions).GetMethod("Cast");
var generic = method.MakeGenericMethod(new[] { model.GetType() });
//var generic = generic.Invoke(new object(), null);
//return generic.Run();
return "Not working yet";
}
else
return "Parent";
}
public static T Cast<T>(this object input)
{
return (T) input;
}
}
【问题讨论】:
-
听起来你要找的是多态性,isn't available for extension methods
-
扩展方法上的多态性正是这...感谢您找到基本相同的旧 SO 问题。我喜欢那里提到的访问者模式,因为应用程序正在做的事情,任何将扩展更改为实体模式的操作都是一个不错的选择。感谢 cmets!
-
一种带有反射方法的方法可以工作:dotnetfiddle.net/iqXu8Y
-
@ASh - 这种方法效果很好。我指定这个问题重新打开,以便您可以根据需要将其作为答案。
-
看起来更简单的方法是
Console.WriteLine(string.Join(", ", commands.Select(c => Extensions.Run(c as dynamic))));取自@Damien_The_Unbeliever 的链接
标签: c# inheritance reflection extension-methods