Как динамически создавать экземпляры класса и вызывать реализацию - PullRequest
0 голосов
/ 07 ноября 2019

У меня есть различные интерфейсы, и я должен иметь возможность вызывать их. Вот базовый класс:

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);
}

Я прочитал эти записи в блоге:

  1. Не используйте Activator.CreateInstance
  2. Выражения Linq
  3. Создание влияний на производительность объектов

Авторы уже знали тип во время компиляции и, следовательно, могли правильно приводить. Я ничего не знаю во время компиляции, поэтому я не могу использовать универсальный метод или типизировать его, используя оператор () или оператор.

ОБНОВЛЕНИЕ : Я думаю, что люди не получаютИдея о том, чего я хочу достичь. так что учтите это. Я сделал пакет Nuget, от которого каждый может зависеть. Где-то в мире кто-то пишет этот код:

    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;
        }
    }

Я хочу, чтобы любой класс, который реализует IActorMessageHandler , мог бы вызывать его метод Handle(Т мсг) . так что, хотя я смог создать его экземпляр (учитывая, что я не использую инъекцию зависимостей), как я могу вызвать метод наиболее эффективным способом?

Есть ли альтернатива отражению?

Ответы [ 2 ]

1 голос
/ 07 ноября 2019

не стоит использовать Activator.CreateInstance это очень дорого. вместо этого вы можете использовать Expression.Lamda для эффективного создания объектов.

  var object =  Expression.Lambda<Func<IActorMessageHandler<TChild>>>(Expression.New(ty.definition.Value.GetConstructor(Type.EmptyTypes) ?? throw new 
    Exception("Failed to create object"))
                        ).Compile()();
1 голос
/ 07 ноября 2019

А как насчет использования ключевого слова dynamic? Это, в основном, оптимизированное отражение, красиво обернутое для вас:

dynamic obj = Activator.CreateInstance(ty.definition, true);
Task t = obj.Handle(msg); //need to define msg before

Обходит проверки во время компиляции и откладывает поиск методов во время выполнения.

Обратите внимание, что при запуске оно не выполнитсявремя, когда невозможно выполнить разрешение для метода Handle.

В этом блоге делается вывод о том, что dynamic заканчивается гораздо быстрее, чем отражение, когда вызывается довольно часто из-за оптимизации кэширования.

...