Given a simplified example of the visitor pattern:
We have to classes A, B which are IVisitables and a visitor BVisitor (which is
able to visit only B)
public interface IVisitor
{
}
public interface IVisitor<T> : IVisitor
{
void Visit(T visitable);
}
public interface IVisitable
{
void Accept(IVisitor visitor);
}
//----------------------------------------------
public class A : IVisitable
{
#region IVisitable Members
public void Accept(IVisitor visitor)
{
IVisitor<A> aVisitor = visitor as IVisitor<A>;
if (aVisitor != null)
{
// calls visitor.Visit(A a) if visitor implements IVisitor<A>
aVisitor.Visit(this);
}
}
#endregion
}
//----------------------------------------------
public class B : IVisitable
{
#region IVisitable Members
public void Accept(IVisitor visitor)
{
IVisitor<B> bVisitor = visitor as IVisitor<B>;
if (bVisitor != null)
{
// calls visitor.Visit(B b) if visitor implements IVisitor<B>
bVisitor.Visit(this);
}
}
#endregion
}
//----------------------------------------------
public class BVisitor :
IVisitor<B>
{
#region IVisitor<B> Members
public void Visit(B b)
{
// do something with b
}
#endregion
}
This code gets compiled to:
var TestSharpKitApp$IVisitor = {fullname: "TestSharpKitApp.IVisitor",
baseTypeName: "System.Object", assemblyName: "TestSharpKitApp", Kind:
"Interface"};
JsTypes.push(TestSharpKitApp$IVisitor);
var TestSharpKitApp$IVisitor$1 = {fullname: "TestSharpKitApp.IVisitor$1",
baseTypeName: "System.Object", assemblyName: "TestSharpKitApp", interfaceNames:
["TestSharpKitApp.IVisitor"], Kind: "Interface"};
JsTypes.push(TestSharpKitApp$IVisitor$1);
var TestSharpKitApp$IVisitable = {fullname: "TestSharpKitApp.IVisitable",
baseTypeName: "System.Object", assemblyName: "TestSharpKitApp", Kind:
"Interface"};
JsTypes.push(TestSharpKitApp$IVisitable);
var TestSharpKitApp$A =
{
fullname: "TestSharpKitApp.A",
baseTypeName: "System.Object",
assemblyName: "TestSharpKitApp",
interfaceNames: ["TestSharpKitApp.IVisitable"],
Kind: "Class",
definition:
{
ctor: function ()
{
System.Object.ctor.call(this);
},
Accept: function (visitor)
{
var aVisitor = As(visitor, TestSharpKitApp.IVisitor$1.ctor);
if (aVisitor != null)
{
aVisitor.Visit(this);
}
}
}
};
JsTypes.push(TestSharpKitApp$A);
var TestSharpKitApp$B =
{
fullname: "TestSharpKitApp.B",
baseTypeName: "System.Object",
assemblyName: "TestSharpKitApp",
interfaceNames: ["TestSharpKitApp.IVisitable"],
Kind: "Class",
definition:
{
ctor: function ()
{
System.Object.ctor.call(this);
},
Accept: function (visitor)
{
var bVisitor = As(visitor, TestSharpKitApp.IVisitor$1.ctor);
if (bVisitor != null)
{
bVisitor.Visit(this);
}
}
}
};
JsTypes.push(TestSharpKitApp$B);
var TestSharpKitApp$BVisitor =
{
fullname: "TestSharpKitApp.BVisitor",
baseTypeName: "System.Object",
assemblyName: "TestSharpKitApp",
interfaceNames: ["TestSharpKitApp.IVisitor$1"],
Kind: "Class",
definition:
{
ctor: function ()
{
System.Object.ctor.call(this);
},
Visit: function (b)
{
}
}
};
JsTypes.push(TestSharpKitApp$BVisitor);
Client code:
IVisitable a = new A();
IVisitable b = new B();
BVisitor bVisitor = new BVisitor();
a.Accept(bVisitor); // shouldn't do anything inside A.Accept(IVisitor), since BVisitor does not implement IVisitor<A>
b.Accept(bVisitor); // should call bVisitor.Visit(B b) from inside B.Accept(IVisitor)
This compiles correctly to
var a = new TestSharpKitApp.A.ctor();
var b = new TestSharpKitApp.B.ctor();
var bVisitor = new TestSharpKitApp.BVisitor.ctor();
a.Accept(bVisitor);
b.Accept(bVisitor);
Executing this code leads to the following problem:
Calling
a.Accept(bVisitor)
in C# would execute the following code
public void Accept(IVisitor visitor)
{
IVisitor<A> aVisitor = visitor as IVisitor<A>;
// in C# the condition above is false, since BVisitor only implements IVisitor<B>, but not IVisitor<A>
if (aVisitor != null)
{
// in C# we only come here for visitors implementing IVisitor<A>
aVisitor.Visit(this);
}
}
The code above is translated to
Accept: function (visitor)
{
var aVisitor = As(visitor, TestSharpKitApp.IVisitor$1.ctor);
// this condition is always true, but it should only be true for visitors implementing IVisitor<A>
if (aVisitor != null)
{
// in js the condition above is incorrectly always true, even for a BVisitor which only implements IVisitor<B>, but not IVisitor<A>
aVisitor.Visit(this);
}
}
We also see that both A.Accept(IVisitor) and B.Accept(IVisitor) compile to the
same code.
IVisitor<A> aVisitor = visitor as IVisitor<A>;
should compile to something like
var aVisitor = As(visitor, TestSharpKitApp.IVisitor$A.ctor);
and
aVisitor.Visit(this);
should compile to
aVisitor.Visit$$A(this);
Original issue reported on code.google.com by zoomer...@gmail.com on 11 Jul 2013 at 7:55
Original issue reported on code.google.com by
zoomer...@gmail.com
on 11 Jul 2013 at 7:55