[英]Less verbose Visitor implementation in C#
Suppose you have an abstract BaseClass
and some derived classes and that you need to visit a List<BaseClass>
with a Visitor
. 假设您有一个抽象
BaseClass
和一些派生类,并且需要使用Visitor
访问一个List<BaseClass>
。 The code would be: 该代码将是:
class Visitor
{
public void Visit(Derived1 visitable) { /*do something*/ }
public void Visit(Derived2 visitable) { /*do something*/ }
public void Visit(Base visitable) { thrown new InvalidOperationException(); }
//other derivatives
}
class Base
{
public virtual void Accept(Visitor visitor) { visitor.Visit(this); }
}
class Derived1 : Base
{
//override is mandatory to have Visit(Derived1 visitable) called
public override void Accept(Visitor visitor) { visitor.Visit(this); }
}
class Derived2 : Base
{
//override is mandatory to have Visit(Derived2 visitable) called
public override void Accept(Visitor visitor) { visitor.Visit(this); }
}
Then you can use all this stuff in a method like: 然后,您可以通过以下方法使用所有这些东西:
var baseClassList = new List<BaseClass>();
//fill baseClassList somehow
var visitor = new Visitor();
foreach(var visitable in baseClassList)
visitable.Accept(visitor);
I think this is a bit too much for a simple dispatching of some operations on different derived classes. 我认为对于在不同的派生类上简单地分派某些操作来说,这有点太多了。
Also, it is counter-intuitive that the chain starts from calling Accept
and not Visit
. 同样,从链开始调用
Accept
而不是Visit
开始是违反直觉的。
Also, if you add a new Derived3
class, you always have to do 2 things: a new overload in the Visitor
AND the override of the Accept
method in the new derived class. 另外,如果添加新的
Derived3
类,则始终必须做两件事: Visitor
的新重载和新派生类中的Accept
方法的覆盖。 Often you forget the second point, getting a runtime error, and other annoying things. 通常,您会忘记第二点,即出现运行时错误和其他令人讨厌的事情。
I'm looking for some simpler and less verbose and more secure implementation of a Visitor
pattern in C#. 我正在寻找一些更简单,更简洁,更安全的C#
Visitor
模式实现。 Is it possible? 可能吗?
Given 2 hypotheses: 给定2个假设:
BaseClass
is abstract and there isn't a "default" behavior for BaseClass
(ie, the Visitor
has a different specific behavior on EVERY derived) BaseClass
是抽象的,没有一个“默认”的行为BaseClass
(即Visitor
中有各个衍生不同的特定行为) I found a solution: 我找到了解决方案:
class DynamicVisitor
{
public void Visit(BaseClass b)
{
Visit((dynamic)b);
}
public void Visit(Derived1 b) { /*do something*/ }
public void Visit(Derived2 b) { /*do something*/ }
}
And you use it this way: 您可以通过以下方式使用它:
var baseClassList = new List<BaseClass>();
//fill baseClassList somehow
var visitor = new Visitor();
foreach(var visitable in baseClassList)
visitor.Visit(visitable);
This way, you don't need any Accept
method, nor its overrides on the visited classes. 这样,您不需要任何
Accept
方法,也不需要在访问的类上重写它。 You only need to write the overloads on the Visitor
. 您只需要在
Visitor
上写入重载。 The overload Visit(BaseClass b)
ensures that any passed parameter derives at least from the BaseClass
, but the dynamic
cast makes the Visitor
to choose the specific overload at runtime. 重载
Visit(BaseClass b)
确保任何传递的参数至少从BaseClass
派生,但是dynamic
强制转换使Visitor
在运行时选择特定的重载。 Obviously, if an instance is exactly of type BaseClass
, you have an infinite recursive call of Visit(Base b)
, and that's because I supposed that BaseClass
is abstract: this way you cannot have an instance of that exact type. 显然,如果实例的类型完全是
BaseClass
,则可以进行Visit(Base b)
的无限递归调用,这是因为我认为BaseClass
是抽象的:这样,您就不能拥有该类型的实例。
I made some performance tests with this approximate load: 我用这种近似的负载进行了一些性能测试:
BaseClass
and 17 DerivedClasses
implementing an IVisitable
interface; IVisitable
接口的BaseClass
和17 DerivedClasses
; BaseClass
to visit; BaseClass
实例的列表; ClassicVisitor
and a DynamicVisitor
both implementing an IVisitor
interface; ClassicVisitor
和DynamicVisitor
都实现了IVisitor
接口; Accept
methods call only the Visit
method and all the Visit
methods are empty, to maximize the measured difference in time. Accept
方法仅调用Visit
方法,而所有Visit
方法都是空的,以最大程度地测量时间差。 Stopwatch
in both Debug and Release mode. Stopwatch
测量的时间。 Result: the DynamicVisitor
is more than 10 times slower (~5/600ms against ~50ms). 结果:
DynamicVisitor
速度慢了10倍以上 (〜5 / 600ms对50ms)。
So, this solution is suitable for contexts in which you have a small amount of calls to make on the visitor. 因此,此解决方案适用于您需要对访问者进行少量调用的情况。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.