So I have an interface called IWorkItem that is implemented in WorkA, WorkB and many other classes.
public interface IWorker<T> where T : IWorkItem
{
void Process(T item);
}
The IWorker<T> interface is implemented in WorkerA (IWorker<WorkA>), WorkerB (IWorker<WorkB>) and many other classes.
public static void ProcessWorkItem(IWorkItem item)
{
(/* find the right worker */).Process(item);
}
Now my problem is: How do find a worker object that is able to process the given IWorkItem?
My first attempts look like this, but the generic type arguments are a problem:
public static class WorkerRepository
{
private static Dictionary<Type, IWorker<???>> RegisteredWorkers =
new Dictionary<Type, IWorker<???>>();
public static void RegisterWorker(IWorker<???> worker)
{
var handled = from iface in worker.GetType().GetInterfaces()
where iface.IsGenericType
where iface.GetGenericTypeDefinition() == typeof(IWorker<>)
select iface.GetGenericArguments()[0];
foreach (var type in handled)
if (!RegisteredWorkers.ContainsKey(type))
RegisteredWorkers[type] = worker;
}
public static void ProcessWorkItem(IWorkItem item)
{
RegisteredWorkers[item.getType()].Process(item);
}
}
So I have the Dictionary that contains the workers. Which type argument do I need here? In Java I could just use ? extends IWorkItem, but do I do that in C#?
Then there is RegisterWorker. You would probably suggest a generic type argument for the entire method, like RegisterWorker<T>(IWorker<T> worker). However, that also won't work, since I would like to dynamically load, instantiate and register Workers.
Is this even the right approach or is there a better way to accomplish this?
I made a few changes but got a solution where you can keep things generic (instead of using objects). Not sure if you even care, but thought to add it as answer and let you decide.
I also wrote a test to check if it actually works, you should be able to copy/paste it.
[TestFixture]
public class WorkerThing
{
[Test]
public void RegisterAndRetrieveWorkers()
{
var repo = new WorkerRepository();
repo.RegisterWorker(new WorkerA());
var workerA = repo.RetrieveWorkerForWorkItem(new WorkItemA());
Assert.IsTrue(workerA is WorkerA);
repo.RegisterWorker(new WorkerB());
var workerB = repo.RetrieveWorkerForWorkItem(new WorkItemB());
Assert.IsTrue(workerB is WorkerB);
}
}
The WorkerRepository class.
public class WorkerRepository
{
private readonly Dictionary<Type, IWorker<IWorkItem>> _registeredWorkers =
new Dictionary<Type, IWorker<IWorkItem>>();
public void RegisterWorker(IWorker<IWorkItem> worker)
{
var type = (from iface in worker.GetType().GetInterfaces()
where iface.IsGenericType
where iface.GetGenericTypeDefinition() == typeof(IWorker<>)
select iface.GetGenericArguments()[0]).First();
if (!_registeredWorkers.ContainsKey(type))
{
_registeredWorkers[type] = worker;
}
}
// You don't need this method, just added it to check if I indeed retrieved the correct type
//
public IWorker<IWorkItem> RetrieveWorkerForWorkItem(IWorkItem item)
{
var type = item.GetType();
var registeredWorker = _registeredWorkers[type];
return registeredWorker;
}
public void ProcessWorkItem(IWorkItem item)
{
var type = item.GetType();
var registeredWorker = _registeredWorkers[type];
registeredWorker.Process(item);
}
}
The work item interfaces & classes.
public interface IWorkItem
{
}
public class WorkItemA : IWorkItem
{
}
public class WorkItemB : IWorkItem
{
}
And here I added the out keyword to allow covariance typing on the interface. That way you can convert WorkerA to IWorker<IWorkItem>. (as in the unit test example)
public interface IWorker<out T> where T : IWorkItem
{
void Process(IWorkItem workItem);
}
public class WorkerA : IWorker<WorkItemA>
{
public void Process(IWorkItem item)
{
}
}
public class WorkerB : IWorker<WorkItemB>
{
public void Process(IWorkItem item)
{
}
}
No object dictionaries. No reflection. I hope the example is useful!
Cheers (and thx for the cool question, it kept me busy for a while :))
It looks like you want something like this:
private static Dictionary<Type, object> RegisteredWorkers = new Dictionary<Type, object>();
public static void RegisterWorker(object worker)
{
var handled = from iface in worker.GetType().GetInterfaces()
where iface.IsGenericType
where iface.GetGenericTypeDefinition() == typeof(Worker<>)
select iface.GetGenericArguments()[0];
foreach (var type in handled)
if (!RegisteredWorkers.ContainsKey(type))
RegisteredWorkers[type] = worker;
}
public static void ProcessWorkItem(WorkItem item)
{
object handler = RegisteredWorkers[item.getType()];
Type workerType = typeof(Worker<>).MakeGenericType(item.GetType());
MethodInfo processMethod = workerType.GetMethod("Process");
processMethod.Invoke(handler, new object[] { item });
}
If you don't want to invoke the handlers through reflection each time you can generate an Action<IWorkItem> handler when you register the handler:
public void RegisterHandler(object handler)
{
var handled = from iface in handler.GetType().GetInterfaces()
where iface.IsGenericType
where iface.GetGenericTypeDefinition() == typeof(IWorker<>)
select iface.GetGenericArguments()[0];
foreach (var type in handled)
{
if (!RegisteredWorkers.ContainsKey(type))
{
Action<IWorkItem> handleAction = HandlerAction(type, handler);
RegisteredWorkers[type] = handleAction;
}
}
}
public void Process(IWorkItem item)
{
Action<IWorkItem> handleAction = RegisteredWorkers[item.GetType()];
handleAction(item);
}
private static Action<IWorkItem> HandlerAction(Type itemType, object handler)
{
var paramExpr = Expression.Parameter(typeof(IWorkItem));
var castExpr = Expression.Convert(paramExpr, itemType);
MethodInfo processMethod = typeof(IWorker<>).MakeGenericType(itemType).GetMethod("Process");
var invokeExpr = Expression.Call(Expression.Constant(handler), processMethod, castExpr);
var lambda = Expression.Lambda<Action<IWorkItem>>(invokeExpr, paramExpr);
return lambda.Compile();
}
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.
If I have the code:
List<Type> Requires = new List<Type>();
How would I constrain the types within this list so they have a common parent?
For example:
List<Type : Component> Requires = new List<Type>()
Edit: A little bit more background so maybe people can understand why I need this. I have a class Entity that contains a list of Components. Each component needs to have a list of Component types that acts as a list of dependencies. So at runtime when you try to add a Component to a Entity it will do a quick check to see if that Entity has the required components already attached to it.
Example:
//Entity.cs
//...
_components = new List<Component>();
//...
public T AddComponent<T>() where T : Component, new()
{
var temp = new T();
if (_components.Exists((x) => x is T)) return null;
foreach (var t in temp.Requires)
{
if (_components.Exists(x => x.GetType() == t)) return null;
}
_components.Add(new T());
temp.gameObject = this;
return temp;
}
//...
//Component.cs
//...
protected internal Entity gameObject;
protected internal List<Type> Requires { get; }
//...
After much work I found a solution to my own problem.
//Component.cs
public abstract class Component {
//...
protected internal Entity gameObject;
private RequiresList _requires;
//...
protected internal RequiresList Requires
{
get => _requires;
private set => _requires = (RequiresList)value.FindAll(x => x.IsSubclassOf(typeof(Component)));
}
//...
public class RequiresList : List<Type>
{
public RequiresList() { }
public RequiresList(IEnumerable<Type> types) : base(types) { }
public RequiresList(int capacity) : base(capacity) { }
public new Type this[int index]
{
get => base[index];
set
{
if (isComp(value))
base[index] = value;
}
}
public new void Add(Type type)
{
if (isComp(type))
base.Add(type);
}
private static bool isComp(Type type)
{
return type.IsSubclassOf(typeof(Component));
}
}
//...
}
//Entity.cs
public abstract class Entity {
//...
_components = new List<Component>();
//...
public T AddComponent<T>() where T : Component, new()
{
var temp = new T();
if (_components.Exists((x) => x is T)) return null;
foreach (var t in temp.Requires)
{
if (_components.Exists(x => x.GetType() == t)) return null;
}
_components.Add(new T());
temp.gameObject = this;
return temp;
}
//...
}
I created a new storage type call RequiresList which checks all System.Types that are inserted into it to see if they are a subclass of Component. I also made sure that if someone tried to replace the list with an entirely new one it will remove any indexes of the new list that aren't Components
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'm looking at a function with this pattern:
if( obj is SpecificClass1 )
{
((SpecificClass1)obj).SomeMethod1();
}
else if( obj is SpecificClass2 )
{
((SpecificClass2)obj).SomeMethod2();
}
else if( obj is SpecificClass3 )
{
((SpecificClass3)obj).SomeMethod3();
}
and get a code analysis warning: CA1800 Do not cast unnecessarily.
What's a good code pattern I can use to replace this code with that will be performant and concise.
Update
I didn't say, but obj is declared with type object.
I originally asked two questions here. I've split one off (which nobody had yet answered anyway): Why wouldn't the compiler optimize these two casts into one?
Interface
The best way would be to introduce an interface that all the types implement. This is only possible if the signatures match (or you don't have too many differences).
Using as
If creating an interface is not an option, you can get rid of the CA message by using the following pattern (though this also introduces unnecessary casts and therefore degrades performance a bit):
var specClass1 = obj as SpecificClass1;
var specClass2 = obj as SpecificClass2;
var specClass3 = obj as SpecificClass3;
if(specClass1 != null)
specClass1.SomeMethod1();
else if(specClass2 != null)
specClass2.SomeMethod2();
else if(specClass3 != null)
specClass3.SomeMethod3();
You can also change it to this structure (from my point of view, the above is better in terms of readability):
var specClass1 = obj as SpecificClass1;
if (specClass1 != null)
specClass1.SomeMethod1();
else
{
var specClass2 = obj as SpecificClass2;
if (specClass2 != null)
specClass2.SomeMethod2();
else
{
var specClass3 = obj as SpecificClass3;
if (specClass3 != null)
specClass3.SomeMethod3();
}
}
Registering the types in a dictionary
Also, if you have many types that you want to check for, you can register them in a dictionary and check against the entries of the dictionary:
var methodRegistrations = new Dictionary<Type, Action<object> act>();
methodRegistrations.Add(typeof(SpecificClass1), x => ((SpecificClass1)x).SomeMethod1());
methodRegistrations.Add(typeof(SpecificClass2), x => ((SpecificClass2)x).SomeMethod2());
methodRegistrations.Add(typeof(SpecificClass3), x => ((SpecificClass3)x).SomeMethod3());
var registrationKey = (from x in methodRegistrations.Keys
where x.IsAssignableFrom(obj.GetType()).FirstOrDefault();
if (registrationKey != null)
{
var act = methodRegistrations[registrationKey];
act(obj);
}
Please note that the registrations are easily extendable and that you can also call methods with different arguments in the action.
To avoid the double casting you could do the following
var objClass1= obj as SpecificClass1;
if(objClass1!=null)
objClass1.SomeMethod1();
Regarding the pattern you could make all these classes implement a common interface and make your method receive the interface.
public void SomeMethod(ISpecificInterface specific)
{
specific.SomeMethod1();
}
Can you do something like this here?
interface IBaseInterface
{
void SomeMethod();
}
public class Implementer1:IBaseInterface
{
public void SomeMethod()
{
throw new NotImplementedException();
}
}
public class Implementer2 : IBaseInterface
{
public void SomeMethod()
{
throw new NotImplementedException();
}
}
public class Implementer3 : IBaseInterface
{
public void SomeMethod()
{
throw new NotImplementedException();
}
}
And then, in caller code:
IBaseInterface concrete = GetInstance();
concrete.SomeMethod();
and GetInstance would create class objects based on conditions.
Your classes can be inherite a ISomeMethodInterface like this:
public interface ISomeMethodInterface
{
void SomeMethod();
}
public class SpecificClass1 : ISomeMethodInterface
{
//some code
public void SomeMethod()
{
}
}
public class SpecificClass2 : ISomeMethodInterface
{
//some code
public void SomeMethod()
{
}
}
public class SpecificClass3 : ISomeMethodInterface
{
//some code
public void SomeMethod()
{
}
}
And in your call:
((ISomeMethodsInterface)obj).SomeMethod();
The most extensible solution would probably be inheriting the concrete class while implementing an interface with a SomeMethod implementation that calls the correct SomeMethodx method on the inherited class. That way, you'll keep the existing interface while still keeping the existing methods.
public interface ISomething {
void SomeMethod();
}
public SpecificClass1Wrapper : SpecificClass1, ISomething {
void SomeMethod() { SomeMethod1(); }
}
If the objects are wrapped in this way before they're stored in the object reference, a cast to ISomething and a call to SomeMethod() will replace your entire if/else combination.
If the object on the other hand comes from code you have no way of extending and terse but still clear is what you're going for, you could create a simple helper method;
private bool CallIfType<T>(object obj, Action<T> action) where T : class
{
var concrete = obj as T;
if (concrete == null)
return false;
action(concrete);
return true;
}
You can then write the calls as a simple expression;
var tmp = CallIfType<SpecificClass1>(obj, x => x.SomeMethod1()) ||
CallIfType<SpecificClass2>(obj, x => x.SomeMethod2()) ||
CallIfType<SpecificClass3>(obj, x => x.SomeMethod3());
if(tmp)
Console.WriteLine("One of the methods was called");
Ok, bit rough, but:
public class BaseClass{}
public class SubClass1 : BaseClass
{
public void SomeMethod1()
{
}
}
public class SubClass2 : BaseClass
{
public void SomeMethod2()
{
}
}
public class Class1
{
public Class1()
{
var test = new SubClass1();
var lookup = new Dictionary<Type, Action<object>>
{
{typeof (SubClass1), o => ((SubClass1) o).SomeMethod1() },
{typeof (SubClass2), o => ((SubClass2) o).SomeMethod2() }
};
//probably best to check the type exists in the dictionary first,
//maybe wrap up the execution into a class of it's own so it's abstracted away
lookup[test.GetType()](test);
}
}
How about writing a method
public static class ObjectExtensions
{
public static bool TryCast<T>(this object from, out T to) where T : class
{
to = from as T;
return to != null;
}
}
and using it:
SpecificClass1 sc1;
SpecificClass2 sc2;
SpecificClass3 sc3;
if( obj.TryCast(out sc1) )
{
sc1.SomeMethod1();
}
else if( obj.TryCast(out sc2) )
{
sc2.SomeMethod2();
}
else if( obj.TryCast(out sc3) )
{
sc3.SomeMethod3();
}
Not sure if I'm missing a goal, but here's an option that should work.
if( obj is SpecificClass1 sc1 )
{
sc1.SomeMethod1();
}
else if( obj is SpecificClass2 sc2 )
{
sc2.SomeMethod2();
}
else if( obj is SpecificClass3 sc3 )
{
sc3.SomeMethod3();
}
else
{
throw new exception();
}
You can also
switch (obj)
{
case SpecificClass1 sc1:
sc1.SomeMethod1();
break;
case SpecificClass2 sc1:
sc2.SomeMethod2();
break;
case SpecificClass3 sc1:
sc3.SomeMethod3();
break;
default:
throw new Exception();
}
Say I have the following method:
private static void SetLastModifiedTimeUser<TEntity>(TEntity entity) where TEntity : class
{
PropertyInfo propertyInfo;
propertyInfo = entity.GetType().GetProperty("LastModifiedUser");
if (propertyInfo != null)
propertyInfo.SetValue(entity, IdentityHelper.UserName, null);
}
As you can see, the method accepts a generic type. Every class passed to this method will contain a property named 'LastModifiedUser'. Is there a way I can access this property without using reflection? I don't think there is, but I thought I'd ask.
Yes, if all your entities have LastModifiedUser property, then you can make all entities inherit from base class, or implement some interface like
public interface IModifyable
{
string LastModifiedUser { get; set; }
}
Then just add this constraint (or make your method non-generic, accepting IModifyable)
where TEntity : class, IModifyable
And your code will look like:
private static void SetLastModifiedTimeUser<TEntity>(TEntity entity)
where TEntity : class, IModifyable
{
entity.LastModifiedUser = IdentityHelper.UserName;
}
Have your class inherit from an interface that defines a LastModifiedUser property.
public interface ILastModifiedUser
{
public string LastModifiedUser { get; set; }
}
Change your method declaration to
private static void SetLastModifiedTimeUser(ILastModifiedUser entity)
If you can't modify all the classes to implement a common interface you can use dynamic
private static void SetLastModifiedTimeUser<TEntity>(TEntity entity) where TEntity : class
{
dynamic d = entity;
d.LastModifiedUser = IdentityHelper.UserName;
}
Otherwise it is as simple as shown by Robert Harvey.
If you can't add an interface to your objects, consider this approach.
The first time it encounters each Type (TEntity), it looks up the property and gets the property's SetMethod. Then, on each use, it creates invokes the method.
var one = new EntityOne();
LastModifiedTimeUserSetter.Set(one);
Console.WriteLine(one.LastModifiedUser);
public static class LastModifiedTimeUserSetter
{
public static void Set<TEntity>(TEntity entity)
{
var method = Properties.GetOrAdd(typeof (TEntity), GetSetMethod);
var action = (Action<string>) Delegate.CreateDelegate(typeof (Action<string>), entity, method);
action(IdentityHelper.UserName);
}
static MethodInfo GetSetMethod(Type type)
{
var prop = type.GetProperty("LastModifiedUser");
if (prop == null)
return null;
return prop.GetSetMethod();
}
static readonly ConcurrentDictionary<Type, MethodInfo> Properties = new ConcurrentDictionary<Type, MethodInfo>();
}
Going further
There is a way to further improve performance by using the System.Reflection.Emit.MethodBuilder. And building a method that takes Entity and sets the property.
public static class LastModifiedTimeUserSetter
{
public static void Set<TEntity>(TEntity entity)
{
var action = (Action<TEntity>) Properties.GetOrAdd(typeof(TEntity), CreateDynamicSetMethodDelegate);
if(action != null)
action(entity);
}
static Delegate CreateDynamicSetMethodDelegate(Type type)
{
return CreateDynamicSetMethod(type).CreateDelegate(GetActionType(type));
}
static DynamicMethod CreateDynamicSetMethod(Type typeWithProperty)
{
var methodBuilder = new DynamicMethod(
"Dynamic_" + typeWithProperty.FullName + "_SetLastModifiedUser",
typeof (void),
new[] {typeWithProperty});
EmitSimpleAssignmentMethod(methodBuilder,
GetIdentityHelperUserNameGetMethod(),
GetPropertySetMethod(typeWithProperty));
return methodBuilder;
}
static MethodInfo GetIdentityHelperUserNameGetMethod()
{
return typeof(IdentityHelper).GetProperty("UserName").GetGetMethod();
}
static MethodInfo GetPropertySetMethod(Type type)
{
var prop = type.GetProperty("LastModifiedUser");
if (prop == null)
return null;
return prop.GetSetMethod();
}
static void EmitSimpleAssignmentMethod(DynamicMethod methodBuilder, MethodInfo getMethod, MethodInfo setMethod)
{
var il = methodBuilder.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.EmitCall(OpCodes.Call, getMethod, null);
il.EmitCall(OpCodes.Call, setMethod, null);
il.Emit(OpCodes.Ret);
}
static Type GetActionType(Type type)
{
return typeof (Action<string>).GetGenericTypeDefinition().MakeGenericType(type);
}
static readonly ConcurrentDictionary<Type, Delegate> Properties = new ConcurrentDictionary<Type, Delegate>();
}
See an Article from MSDN magazine about XBOX Live.