C# 通用参数对象处理程序的工厂
我有一个API,涉及几个无行为参数对象,每个对象都有自己的处理程序:C# 通用参数对象处理程序的工厂,c#,dependency-injection,polymorphism,factory,factory-pattern,C#,Dependency Injection,Polymorphism,Factory,Factory Pattern,我有一个API,涉及几个无行为参数对象,每个对象都有自己的处理程序: //some POCOs public class CustomerChange : IChange{ public int CustomerId {get;set;} public DateTime TimeStamp {get;set;} } public class SomeOtherChange : IChange{ public int AParameter {get;set;}
//some POCOs
public class CustomerChange : IChange{
public int CustomerId {get;set;}
public DateTime TimeStamp {get;set;}
}
public class SomeOtherChange : IChange{
public int AParameter {get;set;}
public string AnotherParameter {get;set;}
public DateTime TimeStamp {get;set;}
}
// stateless handlers that will be resolve with a DI container (Ninject in my case)
public interface IChangeHandler<TChange>{
public Handle(T change);
}
public class CustomerChangeHandler : IChangeHandler<CustomerChange>{
private readonly ICustomerRepository customerRepository;
public CustomerChangeHandler(ICustomerRepository repo){
customerRepository = repo;
}
public Handle(CustomerChange change){
customerRepository.DoStuff(change.CustomerId);
}
}
//一些POCO
公共类CustomerChange:IChange{
public int CustomerId{get;set;}
公共日期时间时间戳{get;set;}
}
公共类其他更改:IChange{
公共int参数{get;set;}
公共字符串另一个参数{get;set;}
公共日期时间时间戳{get;set;}
}
//将使用DI容器解析的无状态处理程序(在我的例子中为Ninject)
公共接口IChangeHandler{
公共处理(T变更);
}
公共类CustomerChangeHandler:IChangeHandler{
专用只读ICCustomerRepository customerRepository;
公共CustomerChangeHandler(ICCustomerRepository repo){
customerRepository=回购;
}
公共句柄(CustomerChange更改){
customerRepository.DoStuff(change.CustomerId);
}
}
等等
当IChange的类型在编译时已知时,这非常有效,但是,我遇到了需要处理未知类型的IChange的情况
在理想的世界中,我希望能够做到以下几点:
public class ChangeHandlerFactory {
public void HandleChange(IChange change){
// get the change handler from the DI container based on the concrete type of IChange
var handlerType = typeof(IChangeHandler<>)
.MakeGenericType(change.GetType());
object handler = container.GetInstance(handlerType); //is this an acceptable way to use a DI container? I would need a dependency on IKernel in this case
handler.Handle(change); // I would need to cast the change object to the appropriate type for the handler or make handler dynamic which seems like it has the potential for hard to debug issues
}
}
公共类changerHandlerFactory{
公共无效处理更改(IChange更改){
//根据IChange的具体类型从DI容器中获取更改处理程序
var handlerType=typeof(IChangeHandler)
.MakeGenericType(change.GetType());
objecthandler=container.GetInstance(handlerType);//这是使用DI容器的一种可接受的方式吗?在这种情况下,我需要依赖IKernel
Handle.Handle(change);//我需要将change对象强制转换为处理程序的适当类型,或者使处理程序成为动态的,这可能会导致难以调试的问题
}
}
我对将处理程序作为动态处理程序的关注是,可能有人做了一些不正确的事情,并出现难以调试的错误
我可以让每个POCO实现一个GetHandler方法来检索处理程序,但这基本上破坏了将它们分开的初衷
在这样的情况下,怎样才能让处理者得到最好的帮助?有没有一种方法可以不使用我的DI容器(ninject)作为服务定位器和/或不使用dynamics来实现这一点?我发现我已经多次遇到这种情况,但还没有找到一种感觉正确的解决方案。最简单的是依赖项反转。让POCO提供一个委托来获取自己的处理程序,因为它显然已经知道它是什么类型
interface IChange
{
IChangeHandler GetHandler(Container container);
}
public class SomeOtherChange : IChange
{
public int AParameter {get;set;}
public string AnotherParameter {get;set;}
public DateTime TimeStamp {get;set;}
public IChangeHandler GetHandler(Container container) => container.GetInstance<SomeOtherChangeHandler>();
}
当然,这就给你留下了一个问题:一旦你拥有了处理器,该如何处理它。同样,您可以让POCO完成以下工作:
public class SomeOtherChange : IChange
{
public int AParameter {get;set;}
public string AnotherParameter {get;set;}
public DateTime TimeStamp {get;set;}
public void GetAndCallHandler(Container container)
{
var handler = container.GetInstance<SomeOtherChangeHandler>();
handler.Handle(this);
}
}
public类SomeOtherChange:IChange
{
公共int参数{get;set;}
公共字符串另一个参数{get;set;}
公共日期时间时间戳{get;set;}
public void GetAndCallHandler(容器)
{
var handler=container.GetInstance();
处理(这个);
}
}
当IChange的类型在运行时已知时,这种方法非常有效。但是,我遇到了一种情况,需要在运行时处理未知类型的IChange。你是说编译时吗?如果您在运行时无法判断某事物是什么类型,那么就会发生一些真正错误的事情:D
public class SomeOtherChange : IChange
{
public int AParameter {get;set;}
public string AnotherParameter {get;set;}
public DateTime TimeStamp {get;set;}
public void GetAndCallHandler(Container container)
{
var handler = container.GetInstance<SomeOtherChangeHandler>();
handler.Handle(this);
}
}