在C#中使用“dynamic”来实现访问者模式

时间:2013-05-01 20:58:00

标签: c# .net dynamic visitor

我有一个应用程序,我在一系列元素上执行操作,操作的确切性质取决于所操作元素的类型。由于封装的原因,元素不适合实现操作;这意味着它不能是元素类型的虚方法,所以'标准'多态不起作用。我提出了与此相关的previous question,并被告知这被称为访客模式。

我以前总是使用基于对象类型的if/elseif调度程序方法实现它,然后调用适当的实现。但是,最近我注意到同样的事情可能是使用dynamic关键字完成,如下所示:

private void ReconcileTips()
{
    foreach (var step in _definition.Steps)
    {
        ReconcileTips((dynamic)step);
    }
}

private void ReconcileTips(IBulkDispenseDefinition bulkDispense)
{
    bulkDispense.TipType = ReconcileTip(bulkDispense.TipType);
}

private void ReconcileTips(ImportScreenDefinition importScreen)
{
    foreach (var usage in importScreen.ReagentUsages)
        usage.TipType = ReconcileTip(usage.TipType);
}

private void ReconcileTips(BuildScreenDefinition buildScreen)
{
    foreach (var function in buildScreen.Functions)
        function.TipType = ReconcileTip(function.TipType);
}

类似的模式可以用于与类结构并行的其他操作,例如为_definition.Steps的每个元素创建视图模型。我们的想法是,编译器基本上将其转换为我之前编写的相同if/elseif逻辑,从而节省了我的努力。所以,有几个问题:

  1. 我没有考虑动态调度的问题吗?我相信这相当于执行一系列if (x is TypeA) Do((TypeA)x) else...,但我可能错了。

  2. 这是否比长if/elseif方法更清晰,更容易理解?

2 个答案:

答案 0 :(得分:9)

  

我没有考虑动态调度的问题吗?我相信这相当于执行一系列if(x是TypeA)Do((TypeA)x)else ......,但我可能错了。

主要问题是如果一个类型在访问者模式中实现了多个接口 - 编译器可能会选择你想要的那个,但如果使用{{1},它可能与你做的选择不同} / if (x is TypeA)逻辑,因为你控制了检查发生的顺序。

  

这比if / elseif方法更长,更容易理解吗?

我个人认为如此。这提供了一个非常干净,相当不错的执行调度,由运行时类型决定,并“正常工作”。难以击败简单,简洁,干净的代码。只需确保(可能)处理从传入的错误类型中获得运行时错误的情况。

答案 1 :(得分:3)

是的,我正在考虑采用这种方法,但决定采用更传统的方法。我从一个接口中派生每个访问者,该接口具有我想为其实现操作的每种类型的访问方法。

如果您要将多个不同的操作实现为访问者,例如。保存和加载操作,您可能希望将来添加更多;使用动态方法,如果您忘记为需要处理的其中一种类型实现操作,则不会出现编译错误。您只会发现程序在运行时崩溃和烧毁的时间。

我希望在编译时确保已经为所有可能的类型实现了任何操作。