如何为实现带共同基类泛型接口的服务编写工厂方法?
如何为实现泛型接口的服务编写工厂方法
现有一组服务,每个都实现了泛型接口IHandleStuff<T>,其中T继承自共同基类Base。需要编写工厂方法返回对应服务实例,但无法确定合适的返回类型,示例代码如下:
public abstract class Base { public int BaseProp { get; set; } } public class Derived1 : Base { public int DerivedProp1 { get; set; } } public class Derived2 : Base { public int DerivedProp2 { get; set; } } public interface IHandleStuff<T> where T : Base { T GetStuff(); void DoStuff(T t); } public class Service1 : IHandleStuff<Derived1> { public Derived1 GetStuff() => new(); public void DoStuff(Derived1 t){} } public class Service2 : IHandleStuff<Derived2> { public Derived2 GetStuff() => new(); public void DoStuff(Derived2 t){} } public class Consumer { public void DoStuff(Base t) { var service = GetServiceFor(t); service.DoStuff(t); } private IHandleStuff<Base> GetServiceFor(Base t) { return t.BaseProp switch { 1 => new Service1(), // 编译错误:无法将Service1转换为IHandleStuff<Base> 2 => new Service2(), // 强制转换编译通过但运行时失败 _ => throw new ArgumentOutOfRangeException() }; } }
补充说明:曾尝试将Consumer中的DoStuff和GetServiceFor改为泛型方法,但实际场景中必须从仅知晓Base类型的非泛型方法调用逻辑,因此该方案不适用。
解决方案
方案1:引入非泛型基础接口
定义一个非泛型的IHandleStuff接口作为泛型接口的基接口,通过显式实现非泛型方法来适配类型转换,既保证类型安全,又满足非泛型调用需求。
// 新增非泛型接口 public interface IHandleStuff { Base GetStuff(); void DoStuff(Base t); } // 修改泛型接口继承非泛型接口 public interface IHandleStuff<T> : IHandleStuff where T : Base { new T GetStuff(); // 重写GetStuff的返回类型 void DoStuff(T t); } // 调整服务类,显式实现非泛型接口 public class Service1 : IHandleStuff<Derived1> { public Derived1 GetStuff() => new(); public void DoStuff(Derived1 t) { } // 显式实现非泛型接口方法 Base IHandleStuff.GetStuff() => GetStuff(); void IHandleStuff.DoStuff(Base t) => DoStuff((Derived1)t); } public class Service2 : IHandleStuff<Derived2> { public Derived2 GetStuff() => new(); public void DoStuff(Derived2 t) { } Base IHandleStuff.GetStuff() => GetStuff(); void IHandleStuff.DoStuff(Base t) => DoStuff((Derived2)t); } // 修改Consumer的工厂方法返回类型 public class Consumer { public void DoStuff(Base t) { var service = GetServiceFor(t); service.DoStuff(t); } private IHandleStuff GetServiceFor(Base t) { return t.BaseProp switch { 1 => new Service1(), 2 => new Service2(), _ => throw new ArgumentOutOfRangeException() }; } }
此方案中,工厂方法返回非泛型接口实例,调用DoStuff时会触发显式实现的方法,在工厂逻辑正确的前提下,强制转换不会出错。
方案2:使用动态类型(Dynamic)
利用dynamic绕过编译时类型检查,直接在运行时解析方法调用,无需修改原有接口结构。
public class Consumer { public void DoStuff(Base t) { dynamic service = GetServiceFor(t); service.DoStuff(t); } private object GetServiceFor(Base t) { return t.BaseProp switch { 1 => new Service1(), 2 => new Service2(), _ => throw new ArgumentOutOfRangeException() }; } }
注意:该方式失去编译时类型校验,若工厂返回的服务与t实际类型不匹配,会抛出运行时异常,需确保类型映射逻辑正确。
方案3:反射调用
通过反射创建服务实例并调用对应方法,适合服务数量多、无需手动维护类型转换的场景。
public class Consumer { public void DoStuff(Base t) { Type serviceType = t.BaseProp switch { 1 => typeof(Service1), 2 => typeof(Service2), _ => throw new ArgumentOutOfRangeException() }; // 创建服务实例 object service = Activator.CreateInstance(serviceType); // 获取并调用DoStuff方法 MethodInfo doStuffMethod = serviceType.GetMethod(nameof(IHandleStuff<Base>.DoStuff)); doStuffMethod.Invoke(service, new[] { t }); } }
此方案灵活性高,但性能略低于前两种,同样依赖类型映射逻辑的准确性。
内容的提问来源于stack exchange,提问作者Ian Horwill
相关产品推荐
相关产品推荐

