Как я могу передать тип в универсальной функции на C#

#c# #signalr

#c# #signalr

Вопрос:

У меня есть следующий код:

     [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
    public class SignalRHub : Attribute
    {
        public readonly string Route;

        public SignalRHub(string Route)
        {
            this.Route = Route;
        }
    }

    [SignalRHub("hubpath")]
    public class TestHub : Hub
    {
        ...
    }
 

Это определяет концентратор SignalR с атрибутом для определения пути.

Я хочу динамически регистрировать концентраторы с атрибутом SignalRHub, поэтому у меня есть следующий код для поиска всех концентраторов:

         // find all hubs
        var Hubs =
            from Assemblies in AppDomain.CurrentDomain.GetAssemblies().AsParallel()
            from Types in Assemblies.GetTypes()
            let Attributes = Types.GetCustomAttributes(typeof(SignalRHub), true)
            where Attributes?.Length > 0
            select new { Type = Types };

        var HubsList = Hubs.ToList();
 

и затем я хочу их зарегистрировать, но здесь у меня проблема:

         foreach (var H in HubsList)
        {
            // get the route attribute
            var Route = string.Empty;
            var Attributes = Attribute.GetCustomAttributes(H.Type);
            foreach (var Attribute in Attributes)
            {
                if (Attribute is SignalRHub A)
                {
                    Route = A.Route;
                    break;
                }
            }

            // register the hub
            if (string.IsNullOrEmpty(Route))
            {
                Logging.Warn($"[Hub] {H.Type.Name} does not have a path, skipping");
            }
            else
            {
                Logging.Info($"[Hub] Registering {H.Type.Name} with path {Route}");
                Application.UseSignalR(R => R.MapHub<H>(Route)); <- this won't compile
            }
 

MapHub требует, чтобы T производился от Hub; поскольку H имеет тип TestHub, это должно быть нормально, но этот синтаксис не работает.

Как я могу заставить это работать?

Комментарии:

1. используйте тип вместо переменной, например Application.UseSignalR(R => R.MapHub<Hub>(Route));

2. Вы должны искать нестандартную систему MapHub, принимающую 2 параметра. Тип и маршрут

3. Не отвечая прямо на вопрос, но, похоже, вы пытаетесь использовать полиморфизм странным образом. Было бы лучше обернуть каждый атрибут в класс about, который знает, как его отправлять, и ваша функция будет вызывать только метод отправки / маршрута атрибута. Тогда ответственность за выбор правильной оболочки атрибута ложится на создателя атрибута.

4. означает ли это, что использование типа, производного от (hub), нормально, и мне не нужно использовать реальный тип? @AndriyShevchenko, не существует универсального вызова MapHub

5. @DrPhil, я не понимаю; можете ли вы указать на пример этого?

Ответ №1:

Мое решение (использует отражение)

 using System;
using System.Reflection;
using Microsoft.AspNetCore.SignalR;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Connections;
//somewhere in your code
private static readonly MethodInfo mapperMethodInfo = 
    typeof(HubRouteBuilder).GetMethod(
        "MapHub",
        new Type [] { 
            typeof(PathString)
        },
        null
    );

// in your mapping code
// replace this:
Application.UseSignalR(R => R.MapHub<H>(Route));  

// with this
Application.UseSignalR(R => 
{
   // pay attention to use of H.Type, R and Route variables
   mapperMethodInfo.MakeGenericMethod(H.Type).Invoke(R, new object [] { Route });
});

 

Ответ №2:

Компилятор недоволен, потому что вы используете переменную экземпляра в качестве универсального типа.

Поскольку переменная экземпляра H указывает на экземпляр концентратора, который вы можете заменить:

 Application.UseSignalR(R => R.MapHub<H>(Route))
 

Автор::

 Application.UseSignalR(R => R.MapHub<Hub>(Route))
 

Комментарии:

1. это не может работать, потому что тип ‘hub’ не может быть создан.

2. Здесь нет экземпляра концентратора (абстрактного класса), ваш TestHub наследует класс Hub, который делает его концентратором. Универсальные типы C # — это типы, не ссылающиеся на экземпляры.