C# 如何使用Unity将通用接口自动注册到该接口的非通用实现

C# 如何使用Unity将通用接口自动注册到该接口的非通用实现,c#,generics,reflection,unity-container,ioc-container,C#,Generics,Reflection,Unity Container,Ioc Container,我的应用程序中有一个模式 公共接口ICommandService { public void Execute(TCommand命令); } 此接口由许多不同的服务类实现。以下是一个例子: public类UpdateWidgetService:ICommandService { 公共void执行(UpdateWidget命令) { ... } } 公共类UpdateWidget { …数据 } 控制器和其他类中依赖这些服务类: 公共类WidgetController { 专用只读IComman

我的应用程序中有一个模式

公共接口ICommandService
{
public void Execute(TCommand命令);
}
此接口由许多不同的服务类实现。以下是一个例子:

public类UpdateWidgetService:ICommandService
{
公共void执行(UpdateWidget命令)
{
...
}
}
公共类UpdateWidget
{
…数据
}
控制器和其他类中依赖这些服务类:

公共类WidgetController
{
专用只读ICommandService服务;
公共WidgetController(ICommandService服务)
{
服务=服务;
}
公共操作结果UpdateWidget(UpdateWidgetViewModel视图模型)
{
...
UpdateWidget命令=viewModel.command;
this.service.Execute(命令);
}
}
如果我要手动注册所有类型映射,我认为类似这样的方法可以工作:

container.RegisterType(typeof(ICommandService),typeof(UpdateWidgetService));
RegisterType(typeof(ICommandService),typeof(CreateWidgetService));
RegisterType(typeof(ICommandService),typeof(deletegimoservice));
RegisterType(typeof(ICommandService),typeof(LaunchNuclearStrikeService));
但正如您所看到的,有一个约定,所有实现
ICommandService
的类都被命名为
[TCommand]Service
,我真的希望按照约定设置某种自动注册。到目前为止,我试过的都没用。我的问题似乎主要是泛型类型参数。以下是我到目前为止的情况:

var container=newunitycontainer();
var assembly=assembly.getExecutionGassembly();
var commandServices=assembly.GetTypes().Where(type=>!type.IsAbstract&&type.Name.EndsWith(“服务”)&&type.GetInterfaces().Single().Name.StartsWith(“ICommandService”).ToList();
foreach(commandServices中的var服务)
{
var serviceInterface=service.GetInterfaces().Single();
var GenericTypeArguments=serviceInterface.GenericTypeArguments.Single();
container.RegisterType(typeof(ICommandService),service);
}

我得到了以下错误:“'genericTypeArgument'是一个变量,但用作类型”。

看起来您的commandServices是类型,所以

foreach(commandServices中的var服务
{
foreach(service.GetInterfaces()中的var interfaceType)
{
container.RegisterType(接口类型、服务);
}
}
试试这个:

 var container = new UnityContainer();

var assembly = Assembly.GetExecutingAssembly();
var commandServices = assembly.GetTypes().Where(type => !type.IsAbstract && type.Name.EndsWith("Service") && type.GetInterfaces().Single().Name.StartsWith("ICommandService")).ToList();

            foreach (var service in commandServices)
            {
                var serviceInterface = service.GetInterfaces().Single();
                var genericTypeArgument = serviceInterface.GenericTypeArguments.Single();

                Type type = Type.GetType($"{genericTypeArgument.UnderlyingSystemType.ToString()}, {genericTypeArgument.Namespace}");

                container.RegisterType(typeof(ICommandService<>), type, new TransientLifetimeManager());

                    
            }
var container=newunitycontainer();
var assembly=assembly.getExecutionGassembly();
var commandServices=assembly.GetTypes().Where(type=>!type.IsAbstract&&type.Name.EndsWith(“服务”)&&type.GetInterfaces().Single().Name.StartsWith(“ICommandService”).ToList();
foreach(commandServices中的var服务)
{
var serviceInterface=service.GetInterfaces().Single();
var GenericTypeArguments=serviceInterface.GenericTypeArguments.Single();
Type Type=Type.GetType($“{genericTypeArgument.underyingSystemType.ToString()},{genericTypeArgument.Namespace}”);
RegisterType(typeof(ICommandService),type,new TransientLifetimeManager());
}

以下是我在各种项目中用来解决这个问题的解决方案,通常是围绕域驱动的事件处理程序(如
IHandlerOf
)或插件系统

首先,我指定要为类型发现包含哪些程序集

var assemblies = RegistrationByConvention.FromSpecificAssemblies(
    typeof(ClassInAssembly1).Assembly,
    typeof(ClassInAssembly2).Assembly,
    typeof(ClassInAssembly3).Assembly);
然后我收集所有非抽象、非值类型和可见的类型

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;

public class RegistrationByConvention
{
    public static IEnumerable<Type> FromSpecificAssemblies(params Assembly[] assemblies)
    {
        return GetTypes(assemblies);
    }

    private static IEnumerable<Type> GetTypes(IEnumerable<Assembly> assemblies)
    {
        return assemblies.SelectMany(assembly =>
        {
            try
            {
                return GetTypes(assembly.DefinedTypes);
            }
            catch (ReflectionTypeLoadException ex)
            {
                return GetTypes(ex.Types.TakeWhile(x => x != null).Select(x => x.GetTypeInfo()));
            }
        });
    }

    private static IEnumerable<Type> GetTypes(IEnumerable<TypeInfo> typeInfos)
    {
        return typeInfos
            .Where(x => x.IsClass & !x.IsAbstract && !x.IsValueType && x.IsVisible)
            .Select(ti => ti.AsType());
    }
}

如果您只想解决错误并使用现有代码,那么您需要使用
Type.MakeGenericType
作为
typeof(ICommandService).MakeGenericType(matchingType)

请不要只发布代码作为答案,还要解释代码的作用以及它是如何解决问题的。带有解释的答案通常更有帮助,质量更好,更容易吸引选票。
foreach (var matchingType in assemblies.Where((type) => { return typeof(BaseWidget).IsAssignableFrom(type); }))
{
    container.RegisterTypes(
        assemblies.Where((type) =>
        {
            return typeof(ICommandService<>).MakeGenericType(matchingType).IsAssignableFrom(type);
        }),
        WithMappings.FromAllInterfaces,
        WithName.TypeName,
        WithLifetime.Transient);
}