0

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:

  1. Dont use Activator.CreateInstance
  2. Linq Expressions
  3. 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?

7
  • What have you tried? You should be able to use the same reflection code you have used to discover and create an instance. Commented Nov 7, 2019 at 13:28
  • i have read a few blog posts about it. Problem is all the blogs know the class at compile time so they typecast it correctly. My case if different. I don't know the class at compile time so I cannot typecast it by using typecasting or even as operator. Commented Nov 7, 2019 at 13:32
  • So you haven't found this stackoverflow.com/questions/2202381/… or dotnetcodr.com/2014/10/10/… ? Commented Nov 7, 2019 at 13:32
  • "how can I call the method in the most efficient way?" - if you're doing all that reflection and LINQ in the constructor, frankly "efficient" already flew out the window... you might want to move actors to be a static readonly field so it only gets built once? (presumably using typeof(TChild) or something instead of the this as TChild stuff?) Commented Nov 7, 2019 at 13:33
  • Another option would be to make your message handler interface non-generic. Then it can be called directly. Commented Nov 7, 2019 at 13:36

2 Answers 2

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()();
Sign up to request clarification or add additional context in comments.

3 Comments

This post seems to conclude that expression construction is slower than activator construction. I'm not an expert though, what do you think?
@CorentinPane I edited my post and now it contains an example of how the users should be using it,
I have done a benchmark and I can see compiled expression is the fastest one
1

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.

2 Comments

is it faster than the tedious MethodInfo and Invoke()?
yes, there are optimizations for dynamic compared to reflection. I'll try to find sources.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.