【发布时间】:2012-12-13 06:50:24
【问题描述】:
问题
我正在使用一个已经存在的库,我无权访问其源代码。这个库代表一个 AST。
我想复制此 AST 的一部分,但在此过程中重命名对变量的引用。由于可以有一个AssignCommand-Object,它包含一个Expression-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)
....
函数现在由List<Command> 组成,其中AssignCommand 是Command 的子类。我假设我可以将Command 传递给Rename 函数,运行时会找到最具体的函数。但是,情况并非如此,所有命令都传递给Command Rename(Command cmd, string prefix)。为什么会这样?有没有办法在不使用丑陋的is-operations 的情况下将调用委托给正确的函数?
小例子
我已将此问题分解为以下 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);
}
}
所以我的问题归结为:“如何在不诉诸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;
}
}
}
【问题讨论】:
-
听起来你想要double dispatch这样的东西。
-
这似乎正是我要找的东西的名称,谢谢。我会相应地标记帖子。然而,由于解决这个问题的常用方法似乎是使用实际的类来实现访问者模式,所以这种方法是不可行的。正如我所说,我无权访问这些类的源代码。我会尝试使用该关键字进行搜索。
标签: c# mono polymorphism overloading dynamic-dispatch