开发者

Variant on Visitor pattern - default no-op Visit method so I don't need to change all my visitors when I add an element type?

I have a set of elements which I want to perform operations on. The classic "Visitor" pattern isn't applicable to my situation because:-

  • My element types are not stable.
  • I want to Visit based on interface implementation, and some of my elements implement multiple interfaces that require visitation by different visitors - this results in an ambiguous call in those types' Accept methods.

Most of my visitors don't care about most of my elements. Even if I could use the classic Visitor pattern, the overwhelming majority of my Visit methods would be no-ops.

I would like a variant of the Visitor pattern which looks like:-

class Visitor
{
  // called when I'm Accepted by a ThingICareAbout
  void Visit(ElementICareAbout e)
  {
    // Do whatever needs done.
  }
  // called when I'm Accepted by anything else
  void Visit(Element e)
  {
    // Do nothing.
  }
}

I came up with the following:-

Related question: c# generic method overload not consistent with abstract Visitor pattern

public interface IAcceptsVisitor
{
  void Accept<T>( IVisitor<T> v );
}

public interface IVisitor<T>
{
  void Visit( T e );
  void Visit<X>( X e );
}

public class Element : IAcceptsVisitor
{
  public bool Visited { get; set; }

  public Element ()
  {
    Visited = false;
  }
  public void Accept<U>( IVisitor<U> v )
  {
    v.Visit( this );
  }
}

public class Visitor : IVisitor<Element>
{
  public void Visit( Element e )
  {
    e.Visited = true;
  }
  public void Visit<X>( X e )
  {
    // Do nothing
  }
}

but that doesn't work because the compiler can only prefer the non-generic Visit method to the generic one if it knows statically at compile-time that it'll work.

  1. Is there a way to make the above work?
  2. Is there another way entirely?

With respect to 2) I've seen Dynamic Dispatching touted as an "advanced" alternative to the Visitor pattern, but is this really "better" than just going:-

foreach (ThingICareAbout in things.OfType<ThingICareAbout>())

Also worthy of note: I'm using .NET 4, so if the dynamic type helps, I'm will开发者_如何学运维ing to give it a shot.

Edit: I've provided my own answer based on the dynamic keyword. However, I'm still extremely interested in hearing about other approaches.


With regards to the Dynamic keyword, this is what I have so far:-

public class ThingIDontCareAbout: IAcceptsVisitor
{
}

public class ThingICareAbout: IAcceptsVisitor
{
  public bool Visited { get; set; }

  public AdvancedElement()
  {
    Visited = false;
  }
}

public class Visitor
{
  public void Visit( IAcceptsVisitor e )
  {
    dynamic d = e;
    this.DynamicVisit( d );
  }

  private void DynamicVisit( IAcceptsVisitor e )
  {
    // Do nothing.
  }

  private void DynamicVisit( ThingICareAbout e )
  {
    e.Visited = true;
  }
}

and you call it with:-

Visitor v = new Visitor();
foreach (IAcceptsVisitor e in things) { v.Visit(e); }

Going to profile this vs type checking. I'm particularly interested in hearing your comments comparing this to:-

foreach (ThingICareAbout e in things.OfType<ThingICareAbout>()) { ...

I like that the dynamic-ness is contained inside the Visitor - and particularly I like that I don't even have to pollute the element types with an Accept method. In particular this means that we can use it to visit types that aren't under our control (typically Expressions or Controls).

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜