问题
I have various interfaces and I need to be able to call them. Here is the base class:
public class MyActorBase<TChild>: ActorBase where TChild : MyActorBase<TChild>
{
public MyActorBase()
{
var actors = ChildClass
.GetInterfaces()
.Where(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IActorMessageHandler<>))
.Select(x=> (arguments: x.GetGenericArguments(), definition: x))
.ToImmutableList();
if (actors.Any())
{
var ty = actors.First();
var obj = Activator.CreateInstance(ty.definition, true);
// how to call method implementation
}
}
protected sealed override bool Receive(object message) => false;
private Type ChildClass => ((this as TChild)?? new object()).GetType();
}
public interface IActorMessageHandler<in T>
{
Task Handle(T msg);
}
I read these blog post:
- Dont use Activator.CreateInstance
- Linq Expressions
- Creating objects performance implications
The writers already knew the type at compile time hence were able to cast correctly. I do not know anything at compile time so I cannot use a generic method or typecast it using () operator or as operator.
UPDATE: I think people are not getting the idea of what I want to achieve. so consider this. I made a nuget package which anyone can depend upon. Somewhere in the world, someone writes this code:
public class MyMessage
{
public int Number { get; }
public MyMessage(int number) => Number = number;
}
public class MyNewActor: MyActorBase<MyNewActor>, IActorMessageHandler<MyMessage>
{
public Task Handle(MyMessage msg)
{
return Task.CompletedTask;
}
}
I want that any class that implements the IActorMessageHandler, i should be able to call its method Handle(T msg). so while I was able to instantiate it (considering that I'm not using any dependency injection) how can I call the method in the most efficient way?
Is there any alternate to reflection?
回答1:
you should not use Activator.CreateInstance
it's very much expensive. instead, you may use Expression.Lamda
to create objects in an efficient way.
var object = Expression.Lambda<Func<IActorMessageHandler<TChild>>>(Expression.New(ty.definition.Value.GetConstructor(Type.EmptyTypes) ?? throw new
Exception("Failed to create object"))
).Compile()();
回答2:
What about using the dynamic
keyword? This is basically optimized reflection nicely wrapped for you:
dynamic obj = Activator.CreateInstance(ty.definition, true);
Task t = obj.Handle(msg); //need to define msg before
It bypasses compile-time checks and defers method look-up at run-time.
Note that it will fail at run-time if no resolution for the Handle
method can be performed.
This blog post concludes that dynamic
ends up being much quicker than reflection when called fairly often because of caching optimizations.
来源:https://stackoverflow.com/questions/58749696/how-to-create-the-class-instances-dynamically-and-call-the-implementation