簡體   English   中英

C# 檢查類型是否實現了具有未知類型的特定泛型接口

[英]C# Check if type implements a specific generic interface with unknown types

我有多個依賴注入處理程序,並希望找到合適的處理程序來解決任務。 我終於找到了相應的處理程序(在 class HandlerResolver ),但我無法將Handler程序作為方法結果返回。

接口:

public interface IMessage
{
}

public interface IHandler<TRoot, in TMessage> where TRoot : class
{
    public abstract TRoot Apply(TRoot root, TMessage message);
}

// Marker interface to register/resolve dependency injected handlers
public interface IHandler
{
}

處理程序:

public class Handler1: IHandler<MyRoot, Message1>, IHandler
{
    public MyRoot Apply(MyRoot aggregateRoot, Message1 message)
    {
        ...
        return aggregateRoot;
    }
}


public class Handler2: IHandler<MyRoot, Message2>, IHandler
{
    public MyRoot Apply(MyRoot aggregateRoot, Message2 message)
    {
        ...
        return aggregateRoot;
    }
}

留言:

public class Message1 : ICaseMessage
{
    ...
}

public class Message2 : ICaseMessage
{
    ...
}

DI注冊:

services.AddScoped<IResolver, HandlerResolver>();
services.AddScoped<IHandler, Handler1>();
services.AddScoped<IHandler, Handler2>();

解決處理程序:

public class HandlerResolver : IResolver
{
    private IEnumerable<IHandler> Handlers { get; } // DI injected handlers
    public HandlerResolver(IEnumerable<IHandler> handlers)
    {
        Handlers = handlers;
    }


    public IHandler<TRoot, TMessage> GetHandler<TRoot, TMessage>(TRoot root, TMessage message)
        where TRoot : class
        where TMessage : class,
    {
        var concreteRootType = root.GetType();
        var concreteMessageType = message.GetType();

        var handlerOrNull = this.Handlers.FirstOrDefault(p =>
        {
            var genericArguments = p.GetType().GetInterfaces().First().GenericTypeArguments;
            return genericArguments[0] == concreteAggregateType && 
                   genericArguments[1] == concreteMessageType;

        });

        if (handlerOrNull == null)
        {
            throw new NotImplementedException($"No Handler Found");
        }
        else
        {
            return handlerOrNull as IHandler<TRoot, TMessage>;
        }
    }
}

返回 handlerOrNull 作為 IHandler<TRoot, TMessage>;

這將始終返回null 我認為這是由於解析。 似乎試圖將其解析為IHandler<TRoot, IMessage>由於某種原因不起作用。

我也試過這個解決方案如何確定一個類型是否實現了一個特定的泛型接口類型,如果泛型類型未知,該接口類型就不起作用。

通常,您應該注冊對象的實際完整類型,即

services.AddScoped<IHandler<MyRoot, Message1>, Handler1>();

這應該可以讓您為您的類型獲得正確的服務:

services.GetRequiredService<IHandler<MyRoot, Message1>>()

至少我認為這是用於 Microsoft.Extensions.DependencyInjection 的正確方法,它不是我熟悉的庫。

請注意,您需要注冊並解析實際類型。 解析IHandler<MyRoot, IMessage>將不起作用,因為這意味着處理程序可以采用任何類型的IMessage參數,但它們不能,它們只能采用Message1 / Message2

逆變的工作方向與您似乎認為的相反,即您將擁有一個Handler1: IHandler<MyRoot, IMessage>可以轉換為IHandler<MyRoot, Message1> 這是有效的,因為處理程序承諾接受所有IMessage實現,而Message1就是這樣一個實現。 但它可能會給解析帶來麻煩,因為解析通常需要精確的類型匹配。

您可以通過手動解決來解決這個問題,即從通用類型 arguments 中為您的接口獲取類型 object,然后手動遍歷這些類型,檢查它們是否可分配。 但是,如果您不想做任何奇怪的事情,我不建議這樣做。

    var handlerType = typeof(IHandler<TRoot, TMessage>);
    Handlers.FirstOrDefault(p => handlerType.IsAssignableFrom(p.GetType()));

實際的處理程序類型應該是IHandler<MyRoot, Message1>IHandler<MyRoot, Message2>取決於泛型類型參數。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM