草庐IT

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

coder 2024-05-30 原文

问题

我正在使用一个已经存在的库,我无法访问它的源代码。这个库代表一个 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/

有关c# - 没有访客模式的动态调度的更多相关文章

  1. ruby-on-rails - Rails - 子类化模型的设计模式是什么? - 2

    我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co

  2. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  3. ruby - 难道Lua没有和Ruby的method_missing相媲美的东西吗? - 2

    我好像记得Lua有类似Ruby的method_missing的东西。还是我记错了? 最佳答案 表的metatable的__index和__newindex可以用于与Ruby的method_missing相同的效果。 关于ruby-难道Lua没有和Ruby的method_missing相媲美的东西吗?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/7732154/

  4. ruby-on-rails - rails 目前在重启后没有安装 - 2

    我有一个奇怪的问题:我在rvm上安装了ruby​​onrails。一切正常,我可以创建项目。但是在我输入“railsnew”时重新启动后,我有“程序'rails'当前未安装。”。SystemUbuntu12.04ruby-v"1.9.3p194"gemlistactionmailer(3.2.5)actionpack(3.2.5)activemodel(3.2.5)activerecord(3.2.5)activeresource(3.2.5)activesupport(3.2.5)arel(3.0.2)builder(3.0.0)bundler(1.1.4)coffee-rails(

  5. ruby - 如何在续集中重新加载表模式? - 2

    鉴于我有以下迁移:Sequel.migrationdoupdoalter_table:usersdoadd_column:is_admin,:default=>falseend#SequelrunsaDESCRIBEtablestatement,whenthemodelisloaded.#Atthispoint,itdoesnotknowthatusershaveais_adminflag.#Soitfails.@user=User.find(:email=>"admin@fancy-startup.example")@user.is_admin=true@user.save!ende

  6. ruby - 在没有 sass 引擎的情况下使用 sass 颜色函数 - 2

    我想在一个没有Sass引擎的类中使用Sass颜色函数。我已经在项目中使用了sassgem,所以我认为搭载会像以下一样简单:classRectangleincludeSass::Script::FunctionsdefcolorSass::Script::Color.new([0x82,0x39,0x06])enddefrender#hamlengineexecutedwithcontextofself#sothatwithintemlateicouldcall#%stop{offset:'0%',stop:{color:lighten(color)}}endend更新:参见上面的#re

  7. c# - 如何在 ruby​​ 中调用 C# dll? - 2

    如何在ruby​​中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL

  8. C# 到 Ruby sha1 base64 编码 - 2

    我正在尝试在Ruby中复制Convert.ToBase64String()行为。这是我的C#代码:varsha1=newSHA1CryptoServiceProvider();varpasswordBytes=Encoding.UTF8.GetBytes("password");varpasswordHash=sha1.ComputeHash(passwordBytes);returnConvert.ToBase64String(passwordHash);//returns"W6ph5Mm5Pz8GgiULbPgzG37mj9g="当我在Ruby中尝试同样的事情时,我得到了相同sha

  9. 没有类的 Ruby 方法? - 2

    大家好!我想知道Ruby中未使用语法ClassName.method_name调用的方法是如何工作的。我头脑中的一些是puts、print、gets、chomp。可以在不使用点运算符的情况下调用这些方法。为什么是这样?他们来自哪里?我怎样才能看到这些方法的完整列表? 最佳答案 Kernel中的所有方法都可用于Object类的所有对象或从Object派生的任何类。您可以使用Kernel.instance_methods列出它们。 关于没有类的Ruby方法?,我们在StackOverflow

  10. ruby - 是否有用于序列化和反序列化各种格式的对象层次结构的模式? - 2

    给定一个复杂的对象层次结构,幸运的是它不包含循环引用,我如何实现支持各种格式的序列化?我不是来讨论实际实现的。相反,我正在寻找可能会派上用场的设计模式提示。更准确地说:我正在使用Ruby,我想解析XML和JSON数据以构建复杂的对象层次结构。此外,应该可以将该层次结构序列化为JSON、XML和可能的HTML。我可以为此使用Builder模式吗?在任何提到的情况下,我都有某种结构化数据-无论是在内存中还是文本中-我想用它来构建其他东西。我认为将序列化逻辑与实际业务逻辑分开会很好,这样我以后就可以轻松支持多种XML格式。 最佳答案 我最

随机推荐