如何在泛型工厂中指向<T>底层类并解决类型转换异常
泛型蔬菜处理器工厂的类型转换错误解决
问题背景代码
蔬菜定义
public interface IVegetable { } public class Potato : IVegetable { } public class Onion : IVegetable { }
处理器定义
public interface IVegetableProcessor<T> where T : IVegetable { string GetColor(T vegetable); } public interface IOnionProcessor : IVegetableProcessor<Onion> { void MakeCry(Onion onion); } public class OnionProcessor : IOnionProcessor { public string GetColor(Onion onion) { return "Purple"; } public void MakeCry(Onion onion) { Console.WriteLine($"{onion} made you cry!"); } }
工厂实现
interface IVegetableProcessorFactory { IVegetableProcessor<T> GetVegetableProcessor<T>(T vegetable) where T : IVegetable; } internal class VegetableProcessorFactory : IVegetableProcessorFactory { public IVegetableProcessor<T> GetVegetableProcessor<T>(T vegetable) where T : IVegetable { object processor = vegetable switch { Onion => new OnionProcessor(), _ => throw new NotImplementedException($"Other vegetables not here yet") }; return (IVegetableProcessor<T>)processor; // 此处运行时报错 } }
报错调用代码与错误信息
调用代码:
static void Main(string[] args) { var onion = new Onion() as IVegetable; var factory = new VegetableProcessorFactory(); var processor = factory.GetVegetableProcessor(onion); Console.WriteLine(processor.GetColor(onion)); Console.ReadLine(); }
错误信息:
System.InvalidCastException: 'Unable to cast object of type 'OnionProcessor' to type 'IVegetableProcessor`1[Vegetables.Program+IVegetable]'.'
错误原因
当onion被转换为IVegetable类型传入工厂时,泛型参数T被编译器推断为IVegetable,但OnionProcessor实现的是IVegetableProcessor<Onion>,而非IVegetableProcessor<IVegetable>。由于C#泛型接口默认是不变量(既不支持协变也不支持逆变),所以无法将IVegetableProcessor<Onion>直接转换为IVegetableProcessor<IVegetable>。
解决方案
方案1:使用动态类型绕过编译时类型推断
修改Main方法中的onion变量类型为dynamic,运行时会根据实际类型(Onion)推断泛型参数T,避免转换错误:
static void Main(string[] args) { dynamic onion = new Onion() as IVegetable; var factory = new VegetableProcessorFactory(); var processor = factory.GetVegetableProcessor(onion); Console.WriteLine(processor.GetColor(onion)); Console.ReadLine(); }
此方法简单直接,无需修改工厂或处理器结构,但会失去编译时类型检查。
方案2:引入非泛型处理器接口
- 定义非泛型的基接口:
public interface IVegetableProcessor { string GetColor(IVegetable vegetable); }
- 修改泛型接口继承该非泛型接口,并显式实现非泛型方法:
public interface IVegetableProcessor<T> : IVegetableProcessor where T : IVegetable { new string GetColor(T vegetable); } public class OnionProcessor : IOnionProcessor { public string GetColor(Onion onion) { return "Purple"; } // 显式实现非泛型接口方法 string IVegetableProcessor.GetColor(IVegetable vegetable) { return GetColor((Onion)vegetable); } public void MakeCry(Onion onion) { Console.WriteLine($"{onion} made you cry!"); } }
- 修改调用代码,直接使用非泛型接口:
static void Main(string[] args) { var onion = new Onion() as IVegetable; var factory = new VegetableProcessorFactory(); var processor = (IVegetableProcessor)factory.GetVegetableProcessor(onion); Console.WriteLine(processor.GetColor(onion)); Console.ReadLine(); }
此方法保留了编译时类型检查,同时支持基类类型的调用。
方案3:通过反射动态匹配类型
修改工厂方法,根据蔬菜的实际类型获取对应的处理器,并通过反射完成类型转换:
internal class VegetableProcessorFactory : IVegetableProcessorFactory { public IVegetableProcessor<T> GetVegetableProcessor<T>(T vegetable) where T : IVegetable { var actualVegetableType = vegetable.GetType(); object processor = actualVegetableType switch { Type t when t == typeof(Onion) => new OnionProcessor(), _ => throw new NotImplementedException($"No processor found for {actualVegetableType.Name}") }; // 获取处理器实现的泛型处理器接口 var processorGenericInterface = processor.GetType() .GetInterfaces() .First(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IVegetableProcessor<>)); // 转换为目标泛型类型 return (IVegetableProcessor<T>)Convert.ChangeType(processor, typeof(IVegetableProcessor<T>)); } }
注意:此方法仅当T是实际蔬菜类型的基类(如IVegetable)且处理器支持隐式转换时有效。
内容的提问来源于stack exchange,提问作者Nick Farsi
相关产品推荐
相关产品推荐

