0

假设您有一个采用通用类型的方法,例如一个枚举 eType 以及一个具体对象。Method 然后根据 enum Type 确定调用哪个方法。每个被调用的私有方法都知道自己的返回类型(根据传入对象的值实例化一个具体的类型化类)。公共方法事先并不知道它将返回哪种类型。

/// 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 返回的对象没有通用的基础/接口,或者它甚至不需要是通用的。enum eType 类似于public static Position Get(int id) http://www.dotnetperls.com/factory中的 ID ,只是标识了主要工厂方法应该做什么。

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

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

4

2 回答 2

3

好的,感谢您的澄清评论,我想我知道您在这里尝试做什么。

首先,您要将 T 限制为 ConcreteTypeA 和 ConcreteTypeB 的基类(我们称之为 BaseType)。

其次,您可能想要删除枚举并决定通过类型参数 T 调用什么方法(这会阻止有人调用GetSomething<TypeA>(eType.B, myClass)

第三,您不需要在 MethodA 和 MethodB 上键入参数,只需让它们返回它们共同的基本类型。

/// 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 T)

于 2013-09-16T14:40:28.543 回答
2

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

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);
    }
}
于 2013-09-16T12:46:59.797 回答