Ale*_*ert 11 c# polymorphism mono overloading dynamic-dispatch
我正在使用已经存在的库,以及我无法访问的源代码.该库代表AST.
我想复制此AST的部分内容,但重命名过程中对变量的引用.由于可以有一个包含Expression对象的AssignCommand-Object,我希望能够使用自己的函数复制每个对象,因此我可以递归地调用它们.但是,由于我无法访问库的代码,我无法添加诸如此类的方法CopyAndRename(string prefix).
因此,我的方法是创建一个Rename具有多个重载的单个函数.因此,我的家庭功能如下:
public static Command Rename(Command cmd, string prefix)
public static AssignCommand Rename(AssignCommand cmd, string prefix)
public static AdditionExpressionRename(AdditionExpression expr, string prefix)
....
Run Code Online (Sandbox Code Playgroud)
函数现在由a组成List<Command>,where AssignCommand是其子类Command.我假设我可以只传递Command给Rename-function,运行时会找到最具体的一个.但是,情况并非如此,所有命令都会传递给Command Rename(Command cmd, string prefix).为什么会这样?有没有办法将调用委托给正确的函数而不使用丑陋的is操作?
我已将此问题解决为以下NUnit-Testcode
using NUnit.Framework;
public class TopClass{
public int retVal;
}
public class SubClassA : TopClass{ }
[TestFixture]
public class ThrowawayTest {
private TopClass Foo (TopClass x) {
x.retVal = 1;
return x;
}
private SubClassA Foo (SubClassA x) {
x.retVal = 2;
return x;
}
[Test]
public void OverloadTest(){
TopClass t = new TopClass();
TopClass t1 = new SubClassA();
SubClassA s1 = new SubClassA();
t = Foo (t);
t1 = Foo (t1);
s1 = Foo (s1);
Assert.AreEqual(1, t.retVal);
Assert.AreEqual(2, s1.retVal);
Assert.AreEqual(2, t1.retVal);
}
}
Run Code Online (Sandbox Code Playgroud)
所以我的问题归结为:"如何在不使用is-checks的情况下以优雅,多态,面向对象的方式修复上述测试?"
我也尝试过如下使用扩展方法.这并没有解决问题,因为它们只是上述方法的语法糖:
using NUnit.Framework;
using ExtensionMethods;
public class TopClass{
public int retVal;
}
public class SubClassA : TopClass{ }
[TestFixture]
public class ThrowawayTest {
private TopClass Foo (TopClass x) {
x.retVal = 1;
return x;
}
private SubClassA Foo (SubClassA x) {
x.retVal = 2;
return x;
}
[Test]
public void OverloadTest(){
TopClass t = new TopClass();
TopClass t1 = new SubClassA();
SubClassA s1 = new SubClassA();
t.Foo(); s1.Foo(); t1.Foo();
Assert.AreEqual(1, t.retVal);
Assert.AreEqual(2, s1.retVal);
Assert.AreEqual(2, t1.retVal);
}
}
namespace ExtensionMethods{
public static class Extensions {
public static void Foo (this TopClass x) {
x.retVal = 1;
}
public static void Foo (this SubClassA x) {
x.retVal = 2;
}
}
}
Run Code Online (Sandbox Code Playgroud)
与Kevin的答案相似,我会考虑利用dynamic关键字.我只想提到另外两种方法.
现在,您实际上并不需要访问源代码,您只需要访问类型本身,即组件.只要类型是public(不是private或internal)这些应该工作:
这个使用与传统访客模式类似的方法.
创建一个访问者对象,每个子类型有一个方法(结束类型,不是中间类或基类,如Command),接收外部对象作为参数.
然后调用它,在编译时你不知道确切类型的特定对象上,只需像这样执行访问者:
visitor.Visit((dynamic)target);
Run Code Online (Sandbox Code Playgroud)
对于包含要访问的子表达式的类型,您还可以在访问者本身内处理递归.
现在,如果您只想处理一些类型,而不是所有类型,那么您可以更简单地创建一个Dictionary索引的处理程序Type.通过这种方式,您可以检查字典是否具有确切类型的处理程序,如果是,则调用它.通过标准调用,可能会强制您在您的处理程序中进行强制转换,或者通过DLR调用,这将不会产生一点性能损失.
| 归档时间: |
|
| 查看次数: |
2987 次 |
| 最近记录: |