C#运行时通过实现接口的Type列表将接口实例转为具体类是否可行
核心结论
你猜测的没错:在C#中无法直接创建/转换得到编译期未知类型的强类型变量,这是由C#静态类型语言的特性决定的:所有变量、表达式的类型必须在编译期可确定,你代码里写的var concrete = fruit as t中的t是运行时才拿到的Type对象,不属于编译期可识别的类型标识,语法层面就不支持。
简化场景的实现方案
你不需要给Apple类加Self方法就可以实现需求,有两种常用方案:
方案1:用dynamic动态绑定
直接将object类型的实例转成dynamic传入方法即可,运行时会自动完成类型匹配和重载解析:
class Apple { public int Size; } class Program { static void EatApple(Apple apple) { } static void Main(string[] args) { object apple = new Apple() { Size = 30 }; // 直接转dynamic传入即可,无需额外定义Self方法 EatApple((dynamic)apple); } }
方案2:用反射调用方法
如果不想用dynamic,可以通过反射拿到方法信息后直接调用:
static void Main(string[] args) { object apple = new Apple() { Size = 30 }; // 获取EatApple方法的元数据 var eatMethod = typeof(Program).GetMethod("EatApple", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic); // 传入实例调用方法 eatMethod.Invoke(null, new object[] { apple }); }
CuttingBoard场景实现方案
如果你需要用到预先拿到的typesImplementingIFruit列表,不想写死if (fruit is Apple)这类判断,可以结合泛型+反射做运行时的类型分发:
class CuttingBoard { // 定义泛型处理方法,这里的T会在运行时绑定为具体的水果类型 private void CutConcreteFruit<T>(T fruit) where T : IFruit { // 此处的fruit已经是强类型的具体水果实例,可以直接调用对应类型的成员、传递给对应重载方法 // 你可以在这里实现不同类型水果的切分逻辑 } public void Cut(Queue<IFruit> fruits) { IEnumerable<Type> typesImplementingIFruit = ReflectionHelper.GetAllTypesThatImplementInterface<IFruit>(typeof(IFruit).Assembly); while(fruits.Count != 0) { var fruit = fruits.Dequeue(); var fruitType = fruit.GetType(); // 校验类型是否属于IFruit的实现类(对应你要用到typesImplementingIFruit列表的要求) if (!typesImplementingIFruit.Contains(fruitType)) { continue; } // 构造封闭泛型方法并调用 var genericCutMethod = typeof(CuttingBoard) .GetMethod("CutConcreteFruit", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic) .MakeGenericMethod(fruitType); genericCutMethod.Invoke(this, new object[] { fruit }); } } }
额外说明
所有方案都没有突破静态类型语言的限制:
- dynamic本质是把类型检查从编译期推迟到了运行期,变量本身的类型在编译期还是
dynamic,不是你运行时拿到的具体类型 - 反射方案本质是绕过了编译器的类型检查,直接在运行时执行方法调用,也不需要你提前声明具体类型的变量
内容的提问来源于stack exchange,提问作者Henrik Landström
相关产品推荐
相关产品推荐

