C# - Generic method calling method which returns concrete type?
假设您有一个采用泛型类型的方法,例如枚举类型和具体对象。然后,该方法根据枚举类型确定要调用的方法。被调用的每个私有方法都知道它自己的返回类型(根据所传入对象的值实例化一个具体类型的类)。公共方法事先不知道它将返回哪种类型。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | /// A Generic method to call individual methods depending on the given enum /// and returns a Generic type. public T GetSomething<T>(enum eType, Model myClass) where T : class { // Do some common tasks here before calling the private methods // ... switch(eType) { case eType.A: return GetMethodA<T>(myClass); case eType.B: return GetMethodB<T>(myClass); } } /// A method that returns a ConcreteTypeA object private T GetMethodA<T>(MyClass myClass) { ConcreteTypeA cta = new ConcreteTypeA(); cta.X = myClass.X; //... etc. return cta; } /// A method that returns a ConcreteTypeA object private T GetMethodB<T>(MyClass myClass) { ConcreteTypeB ctb = new ConcreteTypeB(); ctb.Y = myClass.Y; //... etc. return ctb; } |
- etype=标识要调用的方法
- T=一般返回类型
- getsomething():除了扩展类之外,不知道返回类型。
- getMethoda():获取MyClass对象,初始化、填充、返回ConcreteTypeA
这是基于工厂模式,而不是调用单个方法(使其公开)的替代方法,因此可以在切换案例之前进行公共准备。
Visual Studio说"不能隐式地将类型"concretetypea"转换为"t",这将导致协变和逆变,但我不确定这是否是工厂模式的错误版本。
主要的想法是getsomething()不知道/不关心返回类型,而不关心它是泛型的(它将被使用的地方必须知道他们想要返回哪个类型)。私有方法(methoda,b,…)必须像处理自定义对象创建一样处理具体的类型。concretetypea和b不共享同一个接口或基类。
etype枚举用于标识要调用的方法(参见设计模式:抽象工厂与工厂方法),这通常在工厂中完成。泛型类型t将返回已知类型而不是对象,因为具体的返回类型不实现接口或基类。
与简单工厂的主要区别在于,实际返回的"类型T"仅由调用方和私有方法知道。getsomething返回的对象没有公共的基/接口,或者甚至不需要是通用的。枚举etype类似于
这是一个坏的还是错误的方法?我应该直接使用单独的方法吗(这似乎并不完全符合工厂模式)?
用法是在这里需要初始化不同的类。只需公开各个方法并直接调用它们就很容易了。将所有内容放入单个方法调用中的原因是允许进行公共处理,因为它们都需要一个MyClass实例来进行初始化。
好的,谢谢你的澄清意见。我想我知道你在这里想做什么。
首先,要将t约束到concretetypea和concretetypeb的基类(我们称之为basetype)。
其次,您可能希望移除枚举并决定通过类型参数t调用什么方法(这会停止有人调用getsomething
第三,您不需要在methoda和methodb上键入参数,只需要让它们返回它们的公共基类型。
1 2 3 4 5 6 7 8 9 10 11 | /// A Generic method to call individual methods depending on the given enum /// and returns a Generic type. public T GetSomething<T>(Model myClass) where T : BaseType { // Do some common tasks here before calling the private methods // ... if(typeof(T) == typeof(ConcreteTypeA)) return (T)GetMethodA(myClass); if(typeof(T) == typeof(ConcreteTypeB)) return (T)GetMethodB(myClass); } |
号
您可以将getmethoda(myclass)用作t。
如果必须使用枚举来决定而不是使用类型参数,则必须删除泛型,并将基类返回为类型安全的(或者接受当枚举不匹配时,方法有时会抛出invalidcast)。
解决此问题的最简单方法是使私有生成器方法非泛型,并让它们返回对象。然后,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | private object MethodA(MyClass myClass) { ConcreteTypeA cta = new ConcreteTypeA(); //... return cta; } public T GetSomething<T>(enum eType, Model myClass) where T : class { switch(eType) { case Type.A: return (T)MethodA(myClass); case Type.B: return (T)MethodB(myClass); } } |