【问题标题】:Return an object of one class in a generic method在泛型方法中返回一个类的对象
【发布时间】:2012-06-09 18:00:22
【问题描述】:

我有一个场景,其中有两个类分别使用方法 MethodA 和 MethodB 说 ClassA 和 ClassB。我必须编写泛型方法,根据某些整数变量 x 的条件返回上述类的对象实例。当我尝试下面的代码时,我收到一条错误消息“无法将 ClassA 隐式转换为 T”或“无法将 ClassB 隐式转换为 T”

public ClassA
{
    public void MethodA()
    {
        //method implementation
    }
}

public ClassB
{
    public void MethodB()
    {
        //method implementation
    }
}

泛型方法为

public T MethodGeneric<T>()
{
    int x;
    ClassA objectA = new ClassA();
    ClassB objectB = new ClassB();

    if(x==2)
    {
        return objectA;
    }
    else
    {
        return objectB;
    }
}

【问题讨论】:

  • 给 ClassA 和 B 一个通用的基类或接口,并将 T 限制为该类型。
  • - 或者只是转换:“return (T)objectA;”等等
  • @500-InternalServerError 然后,当有人说MethodGeneric&lt;SomeOtherClass&gt; 时,他们会回复您的同名作为响应。
  • 我想我明白你的意思了,但从例子中看不出 type 参数的目的是什么。
  • @500-InternalServerError 同意。你的名字太容易开玩笑了,我无法抗拒。

标签: c# generics


【解决方案1】:

问题是T 不是ClassA 也不是ClassB

您可以尝试通过强制转换来处理这个问题,如下所示:

public static T MethodGeneric<T>() where T : class
{
    int x = 2;
    ClassA objectA = new ClassA();
    ClassB objectB = new ClassB();

    if (x == 2)
    {
        return objectA as T;
    }
    else
    {
        return objectB as T;
    }
}

但是,如果有人致电 MethodGeneric&lt;ClassC&gt;(),这不会保护您,除非在这种情况下返回 null

如果ClassAClassB 都派生自同一个基类或接口,则可以使这更安全,因为您可以放置​​一个通用约束来减少出错的机会。但是,这仍然不是一种完全安全的工作方式,因为泛型不合适。最好让两个类都实现一个接口(即:IClassBase),然后不使用泛型,而是返回接口:

public IClassBase CreateInstance()
{
    //... 
         return objectA; // This will work fine, provided ClassA implements IClassBase
}

【讨论】:

  • 我不认为你可以那样投射return (T)objectA。您需要先将其推送到对象return (T)(object)objectA;,但我同意其余的。
  • 如果他希望能够在原始类型上按名称调用特定于类型的方法,这一切都是徒劳的。需要多一层抽象。
  • @asawyer 是的 - 除非有明确的合同 - 就像可以使用的接口一样,否则这是毫无意义的。
  • @ReedCopsey 关于接口示例,您会认为接口或带有虚拟覆盖的抽象基础更合适吗?我有时对何时使用一种而不是另一种感到困惑。
  • @asawyer 这取决于 - 如果类型更多是“is-a”类型的关系,我会使用基类,如果共享信息更多是行为,我会使用接口(即:“充当”)。
【解决方案2】:

从您关闭的this double-post 来看,您已经很接近了。您将object 作为类型参数传递,它将再次返回相同的T,即object。这就是为什么您不能使用在ClassA 对象上定义的属性的原因。相反,您应该传递所需的类型,例如 ClassBClassC。可能是这样的:

public T getObject<T>(int i) where T : ClassA
{
    if(i == 1)
    {
        ClassB objB = new ClassB();
        return objB as T;
    }
    else
    {
        ClassC objC = new ClassC();
        return objC as T;
    }
}

public static void main()
{
    var obj = getObject<ClassB>(5); //which wont work anyway since i == 5 !!
    obj.aValue = 20;
    obj.bValue = 30;
    //obj.cValue = 40; this wont work since obj is of type ClassB

    //or 

    var obj = getObject<ClassC>(5);
    obj.aValue = 20;
    //obj.bValue = 30; this wont work since obj is of type ClassC now
    obj.cValue = 40; 
}

我不确定您为什么要检查变量 int i 来决定应该返回什么类型。这不是对泛型的真正使用。真正使用泛型可能如下所示:

public T getObject<T>(int i) where T : ClassA
{
    return new T(); //without the use of int i
}

如果int i 决定返回哪个对象,那为什么还要使用泛型呢?你可以这样做:

public ClassA getObject(int i)
{
    if(i == 1)
    {
        ClassB objB = new ClassB();
        return objB;
    }
    else
    {
        ClassC objC = new ClassC();
        return objC;
    }
}

public static void main()
{
    var obj = getObject(5);
    if (obj is ClassB)
    {
        obj.aValue = 20;
        obj.bValue = 30;
        //obj.cValue = 40; this wont work since obj is of type ClassB
    }
    //or 

    var obj = getObject(5);
    if (obj is ClassC)
    {
        obj.aValue = 20;
        //obj.bValue = 30; this wont work since obj is of type ClassC
        obj.cValue = 40; 
    }
}

但问题是您必须从调用方(主要)检查类型。

如果您想在ClassBClassC 对象上分配属性bValuecValue,那么您应该将这些属性写入ClassA

此外,您仅使用get 访问器,还需要set 来分配值。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-24
    • 1970-01-01
    • 1970-01-01
    • 2021-12-25
    • 2015-03-29
    相关资源
    最近更新 更多