Hello *,
experimenting with Visitor pattern and generic method I found a kind of discrepancy in C#.NET. AFAIK C# compiler prefers an explicit overload to a generic method, therefore the following code:
public abstract class A
{
public abstract void Accept(Visitor v);
}
public class B : A
{
public override void Accept(Visitor v)
{ v.Visit(this); }
}
public class C : A
{
public override void Accept(Visitor v)
{ v.Visit(this); }
}
public class D : A
{
public override void Accept(Visitor v)
{ v.Visit(this); }
}
public class Visitor
{
public void Visit(B b)
{ Console.WriteLine("visiting B"); }
public void Visit(C c)
{ Console.WriteLine("visiting C"); }
public void Visit<T>(T t)
{ Console.WriteLine("visiting generic type: " + typeof(T).Name); }
}
class Program
{
static void Main()
{
A b = new B();
A c = new C();
A d = new D();
Visitor v = new Visitor();
b.Accept(v);
c.Accept(v);
d.Accept(v);
}
}
The output produced is (as expected):
visiting B
visiting C
visiting generic type: D
However this Visitor pattern implementation does not allow to exchange the Visitor class. Introducing an abstract class VisitorBase and forwarding the call to the overloads produces smth. unexpected for me....
public abstract class A
{
public abstract void Accept(VisitorBase v);
}
public class B : A
{
public override void Accept(VisitorBase v)
{ v.Visit(this); }
}
public class C : A
{
public override void Accept(VisitorBase v)
{ v.Visit(this); }
}
public class D : A
{
public override void Accept(VisitorBase v)
{ v.Visit(this); }
}
public abstract class VisitorBase
{
public abstract void Visit<T>(T t);
}
public class Visitor : VisitorBase
{
protected void VisitImpl(B b)
{ Console.WriteLine("visiting B"); }
protected void VisitImpl(C c)
{ Console.WriteLine("visiting C"); }
protected void VisitImpl<T>(T t)
{ Console.WriteLine("visiting generic type: " + typeof(T).Name); }
public override void Visit<T>(T t)
{
VisitImpl(t); //forward the call to VisitorImpl<T> or its overloads
}
}
class Program
{
static void Main()
{
A b = new B();
A c = new C();
A d = new D();
VisitorBase v = new Visitor();
b.Accept(v);
c.Accept(v);
d.Accept(v);
}
}
Now the output is:
visiting generic type: B
visiting generic type: C
visiting generic type: D
Do generic methods only prefer generic methods? Why are no explicit overloads called?
Many thanks,
Ovanes