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);
}