Гость
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / Net Core 3.1 Дженерики, наследование универсальных параметров / 7 сообщений из 7, страница 1 из 1
13.02.2020, 14:47
    #39926278
X-Cite
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Net Core 3.1 Дженерики, наследование универсальных параметров
Добрый день.
Есть такой код:
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
using System;
using Microsoft.Extensions.DependencyInjection;

namespace ConsoleApp12
{
    public interface ICommand { }
    public interface IPipeline<in T> where T : ICommand
    {
        void Run(T aCommand);
    }
    public interface IDispatcher
    {
        public void Execute<TRequest>(TRequest aCommand) where TRequest : ICommand;
    }
    public class CommandA : ICommand { }
    public class CommandB : CommandA { }
    public class CommandC : CommandA { }
    public class CommandD : CommandA { }
    public class Pipeline<T> : IPipeline<T> where T : ICommand
    {
        public void Run(T aCommand)
        {
            Console.WriteLine(aCommand.ToString());
        }
    }
    public class Dispatcher : IDispatcher
    {
        private readonly IServiceProvider _provider;

        public Dispatcher(IServiceProvider aProvider)
        {
            _provider = aProvider;
        }

        public void Execute<TRequest>(TRequest aCommand) where TRequest : ICommand
        {
            var p = typeof(TRequest);
            Console.WriteLine(p.Name);

            var pipeline = _provider.GetService<IPipeline<TRequest>>();
            pipeline.Run(aCommand);
        }

    }


    class Program
    {
        static void Main(string[] args)
        {
            var sc = new ServiceCollection();

            sc.AddScoped<IPipeline<CommandB>, Pipeline<CommandB>>();
            sc.AddScoped<IPipeline<CommandC>, Pipeline<CommandC>>();
            sc.AddScoped<IPipeline<CommandD>, Pipeline<CommandD>>();

            var p = sc.BuildServiceProvider();
            IDispatcher d = new Dispatcher(p);

            CommandA cB = new CommandB();
            d.Execute(cB);
        }
    }
}



Проблема в том, что если сделать
CommandA cB = new CommandB();
d.Execute(cB);
то в TRequest оказывается тип CommandA, а надо каким-то образом CommandB (т.е. реальный), но вызвать нужно именно d.Execute<CommandA>(cB); В реальности известен тоже дженериковский параметр что-то вроде TCommand where TCommand : CommandA, поэтому вызов будет вида d.Execute<TCommand>(cB);
Суть в том, что там где вызывается d.Execute известен только тип CommandA, но параметром передается экземпляр CommandB/C/D
Есть ли какой-то легальный способ получить реальный тип и через ServiceProvider получить реализацию?
...
Рейтинг: 0 / 0
13.02.2020, 15:53
    #39926313
Antonariy
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Net Core 3.1 Дженерики, наследование универсальных параметров
Это не проблема, это ровно то, что вы заказали: CommandA cB. То есть приведение cB от типа CommandB к CommandA.
Нужен CommandB, пишите CommandB cB или var cB.

X-CiteСуть в том, что там где вызывается d.Execute известен только тип CommandAЕсли бы это было правдой, то скомпилировать строку CommandA cB = new CommandB() было бы невозможно.

А если вы говорите про потроха Execute, то там неизвестен ни CommandA ни CommandB, только ICommand.
...
Рейтинг: 0 / 0
13.02.2020, 16:40
    #39926337
vb_sub
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Net Core 3.1 Дженерики, наследование универсальных параметров
ответа к сожалению не знаю, но подскажите где и в каких ситуациях может пригодится приведенный участок кода?
...
Рейтинг: 0 / 0
13.02.2020, 17:14
    #39926360
fkthat
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Net Core 3.1 Дженерики, наследование универсальных параметров
vb_sub
ответа к сожалению не знаю, но подскажите где и в каких ситуациях может пригодится приведенный участок кода?

Типичный паттерн. Курим GoF.
...
Рейтинг: 0 / 0
13.02.2020, 18:07
    #39926375
X-Cite
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Net Core 3.1 Дженерики, наследование универсальных параметров
непосредственно сам CommandB можно получить из aCommand.GetType()
Но тогда как при этом сконструировать IPipeline<CommandB> если CommandB будет не параметром дженерика, а переменной Type.
Может есть способ через рефлексию каким-нибудь образом имея описание IPipeline<T> where T : ICommand и CommandB : ICommand в переменных типа Type, создать переменную Type a = typeof(IPipeline<CommandB>) и тогда потом можно вызвать _provider.GetService(a);
Что-то вроде:
Код: c#
1.
2.
3.
4.
Type a = aCommand.GetType(); // CommandB
Type b = typeof(IPipeline<T>);
Type c = Нечто(a, b); // где Нечто сделает IPipeline<CommandB>
var s = _provider.GetService(c);
...
Рейтинг: 0 / 0
13.02.2020, 18:45
    #39926394
X-Cite
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Net Core 3.1 Дженерики, наследование универсальных параметров
В общем, получилось как-то так...
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
        public void Execute<TRequest>(TRequest aCommand) where TRequest : ICommand
        {
            var typeCommand = aCommand.GetType();
            var typePipeline = typeof(IPipeline<>);

            Type[] typeArgs = { typeCommand };
            var typePipelineCommand = typePipeline.MakeGenericType(typeArgs);

            var pipeline = _provider.GetService(typePipelineCommand);

            var m = typePipelineCommand.GetMethod("Run");

            Object[] args = { aCommand};
            m.Invoke(pipeline, args);
        }


Правда при этом уже TRequest не имеет значения, но можно поступить по другому... Сначала через TRequest ищем сервис, если не нашли, тогда уже через рефлексию, чтобы сэкономить на том, где тип гарантированно известен
...
Рейтинг: 0 / 0
13.02.2020, 21:35
    #39926455
Antonariy
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Net Core 3.1 Дженерики, наследование универсальных параметров
Блин, ну зачем нужна эта дичь с reflection? Все же в начальном посте правильно написано, кроме объявления переменной cB:
...
Рейтинг: 0 / 0
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / Net Core 3.1 Дженерики, наследование универсальных параметров / 7 сообщений из 7, страница 1 из 1
Целевая тема:
Создать новую тему:
Автор:
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]