powered by simpleCommunicator - 2.0.49     © 2025 Programmizd 02
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / Net Core 3.1 Дженерики, наследование универсальных параметров
7 сообщений из 7, страница 1 из 1
Net Core 3.1 Дженерики, наследование универсальных параметров
    #39926278
Фотография X-Cite
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Добрый день.
Есть такой код:
Код: 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
Net Core 3.1 Дженерики, наследование универсальных параметров
    #39926313
Фотография Antonariy
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Это не проблема, это ровно то, что вы заказали: 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
Net Core 3.1 Дженерики, наследование универсальных параметров
    #39926337
vb_sub
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ответа к сожалению не знаю, но подскажите где и в каких ситуациях может пригодится приведенный участок кода?
...
Рейтинг: 0 / 0
Net Core 3.1 Дженерики, наследование универсальных параметров
    #39926360
fkthat
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
vb_sub
ответа к сожалению не знаю, но подскажите где и в каких ситуациях может пригодится приведенный участок кода?

Типичный паттерн. Курим GoF.
...
Рейтинг: 0 / 0
Net Core 3.1 Дженерики, наследование универсальных параметров
    #39926375
Фотография X-Cite
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
непосредственно сам 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
Net Core 3.1 Дженерики, наследование универсальных параметров
    #39926394
Фотография X-Cite
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
В общем, получилось как-то так...
Код: 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
Net Core 3.1 Дженерики, наследование универсальных параметров
    #39926455
Фотография Antonariy
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Блин, ну зачем нужна эта дичь с reflection? Все же в начальном посте правильно написано, кроме объявления переменной cB:
...
Рейтинг: 0 / 0
7 сообщений из 7, страница 1 из 1
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / Net Core 3.1 Дженерики, наследование универсальных параметров
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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