gpt4 book ai didi

c# - 没有访客模式的动态调度

转载 作者:可可西里 更新时间:2023-11-01 08:43:39 24 4
gpt4 key购买 nike

问题

我正在使用一个已经存在的库,我无法访问它的源代码。这个库代表一个 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> 组成, 其中AssignCommandCommand 的子类.我以为我可以通过 CommandRename -function 和运行时会找到最具体的一个。然而,情况并非如此,所有命令都传递给了Command Rename(Command cmd, string prefix)。 .为什么会这样?有没有办法在不使用丑陋的情况下将调用委托(delegate)给正确的函数 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);
}
}

所以我的问题归结为:“如何在不求助于 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;
}
}
}

最佳答案

与凯文的回答类似,我会考虑利用 dynamic 关键字。我将仅提及另外两种方法。

现在,您实际上不需要访问源代码,您只需要访问类型本身,即程序集。只要类型是 public(不是 privateinternal),这些就应该有效:

动态访客

这个使用与传统 Visitor 类似的方法模式。

创建一个访问者对象,每个子类型(最终类型,不是中间类或基类,例如 Command)都有一个方法,接收外部对象作为参数。

然后要调用它,在编译时不知道其确切类型的特定对象上,只需像这样执行访问者:

visitor.Visit((dynamic)target);

对于具有您要访问的子表达式的类型,您还可以在访问者内部处理递归。

处理程序词典

现在,如果您只想处理一些类型,而不是所有类型,创建一个处理程序的 Dictionary 可能更简单,由 Type< 索引。这样您就可以检查字典是否具有确切类型的处理程序,如果有,则调用它。通过可能会强制您在处理程序中强制转换的标准调用,或通过 DLR 调用,这不会但会对性能造成一些影响。

关于c# - 没有访客模式的动态调度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14062160/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com