Is it possible to create a user extendable visitor pattern in C#? (preferably .net 3.5)
I have a set of classes in a library that I wish to add functionality to with the visitor pattern. The problem is that it is also possible for the user of the library to create their own classes. This means that you need to create a special visitor that will accept the new class types but our Accept methods are setup to receive the base type. How can I get the derived classes to call the right method in the derived visitor.
Or is there another way of doing 'if this type, do this"?
Some example code:
/* In library */
namespace VisitorPattern.System
{
interface IThing
{
void Accept(SystemVisitor visitor);
void ThingMethodA(...);
void ThingMethodB(...);
}
class SystemThingA : IThing
{
public void Accept(SystemVisitor visitor) { visitor.Visit(this); }
...ThingMethods...
}
class SystemThingB : IThing
{
public void Accept(SystemVisitor visitor) { visitor.Visit(this); }
...ThingMethods...
}
class SystemThingC : IThing
{
public void Accept(SystemVisitor visitor) { visitor.Visit(this); }
...ThingMethods...
}
class SystemVisitor
{
public SystemVisitor(object specialSystemServices) { }
public virtual void Visit(SystemThingA thing) { Console.WriteLine("SystemThingA"); }
public virtual void Visit(SystemThingB thing) { Console.WriteLine("SystemThingB"); }
public virtual void Visit(SystemThingC thing) { Console.WriteLine("SystemThingC"); }
public virtual void Visit(IThing thing) { Console.WriteLine("sysvis:IThing"); }
}
}
/* in user code */
namespace VisitorPattern.User
{
using VisitorPattern.System;
class UserThingA : IThing
{
public void Accept(SystemVisitor visitor)
{
var userVisitor = visitor as UserVisitor;
if (userVisitor == null) throw new ArgumentException("visitor");
userVisitor.Visit(this);
}
...ThingMethods...
}
class UserThingB : IThing
{
public void Accept(SystemVisitor visitor)
{
var userVisitor = visitor as UserVisitor;
if (userVisitor == null) throw new ArgumentException("visitor");
userVisitor.Visit(this);
}
...ThingMethods...
}
class UserThingC : IThing
{
public void Accept(SystemVisitor visitor)
{
var userVisitor = visitor as UserVisitor;
if (userVisitor == null) throw new ArgumentException("visitor");
userVisitor.Visit(this);
}
...ThingMethods...
}
// ?????
class UserVisitor : SystemVisitor
{
public UserVisitor(object specialSystemServices, object specialUserServices) : base(specialSystemServices) { }
public void Visit(UserThingA thing) { Console.WriteLine("UserThingA"); }
public void Visit(UserThingB thing) { Console.WriteLine("UserThingB"); }
public void Visit(UserThingC thing) { Console.WriteLine("UserThingC"); }
public override void Visit(IThing thing) { Console.WriteLine("uservis:IThing"); }
}
class Program
{
static void Main(string[] args)
{
var visitor = new UserVisitor("systemservice", "userservice");
List<IThing> mylist = new List<IThing> { new UserThingA(), new SystemThingB(), new SystemThingC(), new UserThingC() };
foreach (var thing in mylist)
{
thing.Accept(visitor);
}
}
}
}
Seems like you got it all backwards. First of all, let's talk about the Liskov Substitution Principle. It says that any type should be replaceable by the base type. This also apply to the visitor pattern.
If you have a method called void Accept(IVisitor visitor), it should not matter if a FancyVisitor or a SipleVisitor that is visiting.
The whole idea with the visitor pattern is that the subject (i.e. the class that is being visited) should not know anything about the visitor more than the contract (base class or interface) that it implements. And each Visitor class should be specific for a certain class being visited.
And that's the problem with your code. You are trying to make a general Visitor class that can visit all your system components. That's plain wrong.
As I see it, you have two options:
You want to collect the same kind of information from all system components.
Easy. Create a new interface which all system components implement. Then change the visitor to Visit(ISystemCompoent subject).
You want to collect different kinds of information from each system component
Then you need to create different visitor base classes (or interfaces).
No, it is not possible to mix the visitor pattern with visions of an extensible class hierarchy. They are mutually exclusive.
One solution from this series of blog posts could involve using "interfaces and dynamic type casts to overcome the Visitor pattern’s problems with extensible class hierarchies"
eg:
class UserThingC : IThing
{
public void Accept(SystemVisitor visitor)
{
var userVisitor = visitor as UserVisitor;
if (userVisitor == null) throw new ArgumentException("visitor");
userVisitor.Visit(this);
}
}
(Not saying this is the best, just an alternative)
Yes, you can do this using reflection. The main idea of using a visitor pattern is for double dispatch. Using reflection you can get all the Visit(...) methods from any visitor and invoke the right method based on the parameter type of the Visit method.
If you go this route, you won't necessarily need an inheritance hierarchy for the visitor or the element you are visiting. In fact, the element classes won't even need to know about the visitor interface (or base class).
To make it clear, below is a code sample that implements a generic visitor that uses reflection to do double dispatch. Using the GenericVisitor<T>::AcceptVisitor(...), you can get any element (derived or not) to call the right method in the any visitor (derived or not) as long as the visitor T defines a method Visit(...) for that particular element class.
using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
namespace VisitorPattern
{
class GenericVisitor<T>
{
// Dictionary whose key is the parameter type and value is the MethodInfo for method "Visit(ParameterType)"
static Dictionary<Type, MethodInfo> s_visitorMethodDict;
static GenericVisitor()
{
s_visitorMethodDict = new Dictionary<Type, MethodInfo>();
Type visitorType = typeof(T);
MethodInfo[] visitorMethods = visitorType.GetMethods();
// Loop through all the methods in class T with the name "Visit".
foreach (MethodInfo mi in visitorMethods)
{
if (mi.Name != "Visit")
continue;
// Ignore methods with parameters > 1.
ParameterInfo[] parameters = mi.GetParameters();
if (parameters.Length != 1)
continue;
// Store the method in the dictionary with the parameter type as the key.
ParameterInfo pi = parameters[0];
if (!s_visitorMethodDict.ContainsKey(pi.ParameterType))
s_visitorMethodDict.Add(pi.ParameterType, mi);
}
}
public static bool AcceptVisitor(object element, T visitor)
{
if (element == null || visitor == null)
return false;
Type elementType = element.GetType();
if (!s_visitorMethodDict.ContainsKey(elementType))
return false;
// Get the "Visit" method on the visitor that takes parameter of the elementType
MethodInfo mi = s_visitorMethodDict[elementType];
// Dispatch!
mi.Invoke(visitor, new object[] { element });
return true;
}
}
// Element classes (note: they don't necessarily have to be derived from a base class.)
class A { }
class B { }
class Visitor
{
public void Visit(A a) { System.Console.WriteLine("Visitor: Visited A"); }
public void Visit(B b) { System.Console.WriteLine("Visitor: Visited B"); }
}
interface IVisitor
{
void Visit(A a);
void Visit(B b);
}
class DerivedVisitor : IVisitor
{
public void Visit(A a) { System.Console.WriteLine("DerivedVisitor: Visited A"); }
public void Visit(B b) { System.Console.WriteLine("DerivedVisitor: Visited B"); }
}
class Program
{
static void Main(string[] args)
{
Object a = new A();
Object b = new B();
// Example of Visitor that doesn't use inheritance.
Visitor v1 = new Visitor();
GenericVisitor<Visitor>.AcceptVisitor(a, v1);
GenericVisitor<Visitor>.AcceptVisitor(b, v1);
// Example of Visitor that uses inheritance.
IVisitor v2 = new DerivedVisitor();
GenericVisitor<IVisitor>.AcceptVisitor(a, v2);
GenericVisitor<IVisitor>.AcceptVisitor(b, v2);
}
}
}
You could use the new dynamic keyword like this:
public class Visitable1
{
public void Accept(dynamic visitor)
{
visitor.Visit(this);
}
}
public class DynamicVisitor
{
public void Visit(Visitable1 token)
{
// Call token methods/properties
}
}
However, you expose your code to MissingMethodException
Yes, you can do this.
Change all your UserThing's Accept(SystemVisitor visitor)methods to accept a UserVisitor instead.
Add an abstract base class for all your UserThings
In the abstract base class add an Accept method that attempts to cast the visitor from a SystemVisitor to a UserVisitor. if it succeeds it calls the Accept method on the UserThing.
public override void Accept(SystemVisitor visitor)
{
var visitorAsUser = visitor as UserVisitor;
if (visitorAsUser != null)
return this.Accept(UserVisitor);
}
The SystemVisitor still knows nothing about your UserThings and an existing SystemVisitor cannot visit them, but your UserVisitor can.
Related
I have an external DLL that contains some business logic.
I would like to perform something like this:
Load the DLL in runtime
Filter available types by some criteria.
Create target type instance
i.e. dynamic c = Activator.CreateInstance(type);
Cast previously created instance to some interface to pass it into handler method
so external dll will contains something like that:
namespace External.Handler.Namespace
{
using System;
public interface IHandler {
int Process(string arg);
int ProcessV2(string arg);
}
public class HandlerImpl : IHandler
{
public int Process(string arg)
{
// ... implementation
return 0;
}
public int ProcessV2(string arg)
{
// ... implementation
return 0;
}
}
}
and at target service I would like to load it and try to cast to internal interface
namespace My.Target.Namespace
{
using System;
using System.Reflection;
public interface IInternalHandler {
int Process(string arg)
}
class Program
{
static void Main(string[] args)
{
var DLL = Assembly.LoadFile(#"path\to\dll");
foreach(Type type in DLL.GetExportedTypes())
{
dynamic c = Activator.CreateInstance(type);
try
{
// I would like to know: how perform it?
var typedInstance = (IInternalInterface) c;
Handle(typedInstance);
}
catch {}
}
Console.ReadLine();
}
public static void Handle(IInternalHandler handler, string arg) {
int result = handler.Process(arg);
Console.log(result);
}
}
}
To summarize: Is it possible to convert dynamic to A PARTIALLY match interface?
Your HandlerImpl class doesn't implement IInternalHandler, so you can't cast it to that interface.
You would need to wrap the dynamic instance in a class which does implement that interface. For example:
internal class InternalHandlerWrapper : IInternalHandler
{
private readonly object _handler;
public InternalHandlerWrapper(object handler)
{
_handler = handler;
}
public int Process(string arg)
{
dynamic handler = _handler;
handler.Process(arg);
}
}
Usage:
foreach(Type type in DLL.GetExportedTypes())
{
if (type.IsAbstract || type.IsInterface) continue;
try
{
object c = Activator.CreateInstance(type);
var typedInstance = new InternalHandlerWrapper(c);
Handle(typedInstance);
}
catch {}
}
NB: The GetExportedTypes will also return the IHandler interface itself. If you pass that type to Activator.CreateInstance, you will get an exception. You need to filter out abstract and interface types from your loop.
According to https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-8.0/default-interface-methods
It is possible to explicitly invoke an interface base implementation with the following syntax.
base(IInterfaceType).Method();
But this doesn't seem to be implemented yet.
Is there a workaround (e.g reflection) to achieve this?
Example code to illustrate the problem
interface IA
{
void M()
{
Console.WriteLine("IA.M");
}
}
interface IB : IA
{
void IA.M()
{
Console.WriteLine("IB.M");
}
}
interface IC : IA
{
void IA.M()
{
Console.WriteLine("IC.M");
}
}
class D : IA, IB, IC
{
public void M()
{
// base(IB).M(); Is not yet supported apparently
((IB)this).M(); // Throws stack overflow
}
}
class Program
{
static void Main(string[] args)
{
D d = new D();
d.M();
}
}
The link in the question points to a version of the proposal copied from the proposal document in Github
The feature was cut in April 2019
Conclusion
Cut base() syntax for C# 8. We intend to bring this back in the next major release.
The design meeting doc explains that without runtime support (which wouldn't be available in time), the implementation would be workable at best for C# but not VB.NET.
If B.M is not present at run time, A.M() will be called. For base() and interfaces, this is not supported by the runtime, so the call will throw an exception instead. We'd like to add support for this in the runtime, but it is too expensive to make this release.
We have some workarounds, but they do not have the behavior we want, and are not the preferred codegen. Our implementation for C# is somewhat workable, although not exactly what we would like, but the VB implementation would be much more difficult. Moreover, the implementation for VB would require the interface implementation methods to be public API surface.
As for the infinite recursion, this
public void M()
{
((IB)this).M(); // Throws stack overflow
}
That's essentially
public void M()
{
M(); // Throws stack overflow
}
Default interface members are called the same way explicitly implemented interface methods are, through the interface. Besides, you're asking to call the method on this, not base.
There is a workaround.
I got it working, using GetFunctionPointer
Warning do not use this code
static class BaseInterfaceInvocationExtension
{
private static readonly string invalidExpressionMessage = "Invalid expression.";
public static void Base<TInterface>(this TInterface owner, Expression<Action<TInterface>> selector)
{
if (selector.Body is MethodCallExpression methodCallExpression)
{
MethodInfo methodInfo = methodCallExpression.Method;
string name = methodInfo.DeclaringType.FullName + "." + methodInfo.Name;
Type type = owner.GetType();
InterfaceMapping interfaceMapping = type.GetInterfaceMap(typeof(TInterface));
var map = interfaceMapping;
var interfaceMethod = map.InterfaceMethods.First(info =>
info.Name == name);
var functionPointer = interfaceMethod.MethodHandle.GetFunctionPointer();
var x = methodCallExpression.Arguments.Select(expression =>
{
if (expression is ConstantExpression constantExpression)
{
return constantExpression.Value;
}
var lambda = Expression.Lambda(Expression.Convert(expression, expression.Type));
return lambda.Compile().DynamicInvoke();
}).ToArray();
Type actionType = null;
if (x.Length == 0)
{
actionType = typeof(Action);
}else if (x.Length == 1)
{
actionType = typeof(Action<>);
}
else if (x.Length == 2)
{
actionType = typeof(Action<,>);
}
var genericType = actionType.MakeGenericType(methodInfo.GetParameters().Select(t => t.ParameterType).ToArray());
var instance = Activator.CreateInstance(genericType, owner, functionPointer);
instance.GetType().GetMethod("Invoke").Invoke(instance, x);
}
else
{
throw new Exception(invalidExpressionMessage);
}
}
}
class D : IA, IB, IC
{
public void M(int test)
{
this.Base<IB>(d => d.M(test));
}
}
class Program
{
static void Main(string[] args)
{
D d = new D();
d.M(12);
Console.ReadKey();
}
}
This is a workaround. It isn't ideal. Perhaps it will help someone.
class C : IB
{
public void IBM() => (this as IB).M();
}
class D : IA, IB, IC
{
private C _c = new C();
public void M()
{
_c.IBM();
}
}
Alternatively, this could work:
...
interface IB : IA
{
void IA.M()
{
IB_M();
}
void IB_M()
{
Console.WriteLine("IB.M");
}
}
...
class D : IA, IB, IC
{
public void M()
{
(this as IB).IB_M();
}
}
Not ideal either but less verbose.
It is going to be hard to explain why Im doing the things im about to show you, but they have a reason so stay with me here. (suggestions are welcome).
I have a Functor which invokes a method on its input.
!Please note! the functor is actually an extension method so there must be a typing inference.
Also, I have an abstract class with 2 childs and an interface which demands a method signature.
The example code looks like this:
public sealed class AbstractionTester
{
internal static void Run()
{
// The functor here accepts A type but in my original code its just a generic type.
// I wanted to keep it simple for this example only
Func<A, bool> func = a =>
{
a.CallMe(); //Displays "Error"
return true;
};
B obj = new B();
func(obj);
}
}
internal interface ICallMe<T>
where T : MyEntity
{
T CallMe();
}
//Just a class which holds data I would like to store about every object I have, for example: CreateDate
internal abstract class MyEntity
{ }
internal abstract class A : MyEntity, ICallMe<A>
{
//some other fields i would like to store..
// This method here must never be invoked
public A CallMe()
{
//throw new Exception();
Console.WriteLine("Error");
return this;
}
}
internal class B : A, ICallMe<B>
{
public new B CallMe()
{
Console.WriteLine("B");
return this;
}
}
internal class C : A, ICallMe<C>
{
public new C CallMe()
{
Console.WriteLine("C");
return this;
}
}
Everytime I call Run() the result is the Error is yeilded to the screen.
What can I do to enforce that this functor I have won't execute the method in the parent class.
Functor will never receive an instance of A anyway, because A is abstract (I mean pure A, not child of A)
Additional info:
I must explicity write the return types of CallMe in class B and C. I CANNOT change them to type A.
I need to keep the type of A (or something similar) in the functor because I need to infer the type for some code continuation.
It is really weird implementation. Why dont you use Visitor pattern?
Then you can do:
static void Main(string[] args)
{
Element a = new A();
Element b = new B();
Element c = new C();
ICallMe callMe = new CallMe();
a.accept(callMe);
b.accept(callMe);
c.accept(callMe);
}
Implementation below:
public interface ICallMe
{
void Visit(A a);
void Visit(B b);
void Visit(C c);
}
public class CallMe : ICallMe
{
public void Visit(A c)
{
Console.WriteLine("A");
}
public void Visit(B b)
{
Console.WriteLine("B");
}
public void Visit(C a)
{
Console.WriteLine("C");
}
}
interface Element
{
void accept(ICallMe visitor);
}
public class A : Element
{
public void accept(ICallMe visitor)
{
visitor.Visit(this);
}
}
public class B : Element
{
public void accept(ICallMe visitor)
{
visitor.Visit(this);
}
}
public class C : Element
{
public void accept(ICallMe visitor)
{
visitor.Visit(this);
}
}
Here is a solution that works without defining public A CallMe() as virtual. This has the benefit that child classes can define their CallMe() as new so they can return B or C. But it requires that you can make the classes public instead of internal (or you will get an error).
Use dynamic dispatch to call the actual runtime type instead of the type declared in the interface:
Func<A, bool> func = a => {
var runtimeType = (dynamic)a;
runtimeType.CallMe();
return true;
};
.net Fiddle
There is a specific language feature for this; interface reimplementation.
Reimplement explicitly the interface and make the generic functor take an ICallable<T>:
internal class B : A, ICallMe<B>
{
B ICallable<B>.CallMe()
{
Console.WriteLine("B");
return this;
}
}
internal class C : A, ICallMe<C>
{
B ICallable<C>.CallMe()
{
Console.WriteLine("B");
return this;
}
}
And your functor should be:
Func<T, bool> func = a => ...
And T should be constrained (at method or class level) to ICallable<T>.
UPDATE: If the functor is really an extension code, I'm not sure what the issue is:
public static bool MyEnxtensionMethod<T>(T argument)
where T: ICallable<T>
{
argument.CallMe();
return true;
}
Why do you need to keep A anywhere?
The best way to ensure that A's CallMe method is never invoked is for it to not exist.
internal abstract class MyEntity
{ }
internal abstract class A : MyEntity
{ }
Now it can never be invoked as you required.
Now make the interface covariant:
internal interface ICallMe<out T>
where T : MyEntity
{
T CallMe();
}
Then change Func<A, bool> to Func<ICallMe<A>, bool>
public sealed class AbstractionTester
{
internal static void Run()
{
// The functor here accepts A type but in my original code its just a generic type.
// I wanted to keep it simple for this example only
Func<ICallMe<A>, bool> func = a =>
{
a.CallMe(); //Displays "B"
return true;
};
B obj = new B();
func(obj);
}
}
I have the following classes (I can't change them, they are not in my control):
public abstract class BusinessBase { }
public class A : BusinessBase { }
public class B : BusinessBase { }
public class FooOne
{
public void Foo<T>(FooDelegates.Func<T> func) where T : BusinessBase { ... }
}
public class FooTwo
{
public void Foo<T>(FooDelegates.Func<T> func) where T : BusinessBase { ... }
}
public static class FooDelegates
{
public delegate TResult Func<TResult>();
}
Creating a delegate and calling the method is pretty straightforward:
var f1 = new FooOne();
f1.Foo(() => new A());
However, trying to use reflection to do this is proving to be a bit complicated. I have the following function which I cannot seem to finish:
public class GenericHelper
{
// Parent can be A or B or etc...
// Child is FooOne or FooTwo or etc...
public void Relate(object parent, object child)
{
var mi = child.GetType().GetMethod("Foo");
var gmi = mi.MakeGenericMethod(parent.GetType());
// This next part obviously won't compile...
var del = typeof(FooDelegates.Func<>).MakeGenericType(parent.GetType());
FooDelegates.Func<parent.GetType()> del = () => parent;
gmi.Invoke(child, new object[] { del });
}
}
How do I correctly generate a FooDelegates.Func<T> where T is the parent type and I have an anonymous method as the assigned method?
You can use expression trees to compile new functions at runtime:
Expression.Lambda(del, Expression.Constant(parent)).Compile()
I have the following C# test code:
class MyItem
{
MyItem( int a ) {}
}
class MyContainer< T >
where T : MyItem, new()
{
public void CreateItem()
{
T oItem = new T( 10 );
}
}
Visual Studio can't compile it, the error is at line where 'new' is used:
'T': cannot provide arguments when creating an instance of a variable type
Is it possible in C# to create an object of generic type with non-parameterless constructor? It's no problem to do such thing in C++ templates, so i'm very curious why i can't do same thing in C#. Maybe some additional 'where' is required or syntax is different?
C#, and VB.Net for that matter, do not support the notion of constraining a generic to have a constructor with specific parameters. It only supports constraining to have an empty constructor.
One work around is to have the caller pass in a factory lambda to create the value. For instance
public void CreateItem(Func<int,T> del) {
T oItem = del(10);
}
Call site
CreateItem(x => new SomeClass(x));
It can be done with reflection:
public void CreateItem()
{
int constructorparm1 = 10;
T oItem = Activator.CreateInstance(typeof(T), constructorparm1) as T;
}
But there is no generic constraint to ensure that T implements the desired constructor, so I wouldn't advise doing this unless you are careful to declare that constructor in every type that implements the interface.
There's no such generic constraint, so it's not possible directly (this is a CLR limitation). If you want this, you have to provide a factory class (which has a parameterless constructor), and pass it as a second generic type parameter.
IMO, the best approach here is an initialize method, i.e.
interface ISomeInterface {
void Init(int i);
}
class Foo : ISomeInterface {
void ISomeInterface.Init(int i) { /* ... */ }
}
static class Program {
static T Create<T>(int i) where T : class, ISomeInterface, new() {
T t = new T();
t.Init(i);
return t;
}
static void Main() {
Foo foo = Create<Foo>(123);
}
}
However, you can do what you want with Expression (but without compile-time support):
using System;
using System.Linq.Expressions;
class Foo {
public Foo(int i) { /* ... */ }
}
static class Program {
static T Create<T>(int i) {
return CtorCache<T>.Create(i);
}
static class CtorCache<T> {
static Func<int, T> ctor;
public static T Create(int i) {
if (ctor == null) ctor = CreateCtor();
return ctor(i);
}
static Func<int, T> CreateCtor() {
var param = Expression.Parameter(typeof(int), "i");
var ci = typeof(T).GetConstructor(new[] {typeof(int)});
if(ci == null) throw new InvalidOperationException("No such ctor");
var body = Expression.New(ci, param);
return Expression.Lambda<Func<int, T>>(body, param).Compile();
}
}
static void Main() {
Foo foo = Create<Foo>(123);
}
}
Note that this caches and reuses the delegate for performance.
One pattern I use is to have the constrained class implement an interface which defines an Init method with the appropriate signature:
interface IMyItem
{
void Init(int a);
}
class MyItem : IMyItem
{
MyItem() {}
void Init(int a) { }
}
class MyContainer< T >
where T : MyItem, IMyItem, new()
{
public void CreateItem()
{
T oItem = new T();
oItem.Init( 10 );
}
}