关于C#:C# – 返回具体类型的通用方法调用方法?

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类似于public static Position Get(int id)http://www.dotnetperls.com/factory中的ID,它只标识主工厂方法应该做什么。

这是一个坏的还是错误的方法?我应该直接使用单独的方法吗(这似乎并不完全符合工厂模式)?

用法是在这里需要初始化不同的类。只需公开各个方法并直接调用它们就很容易了。将所有内容放入单个方法调用中的原因是允许进行公共处理,因为它们都需要一个MyClass实例来进行初始化。


好的,谢谢你的澄清意见。我想我知道你在这里想做什么。

首先,要将t约束到concretetypea和concretetypeb的基类(我们称之为basetype)。

其次,您可能希望移除枚举并决定通过类型参数t调用什么方法(这会停止有人调用getsomething(etype.b,myclass))。

第三,您不需要在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)。


解决此问题的最简单方法是使私有生成器方法非泛型,并让它们返回对象。然后,GetSomething方法可以将返回值强制转换为给定的类型T

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);
    }
}