具有多个约束的通用

时间:2012-12-06 16:55:24

标签: c# generics inheritance

我正在尝试调用一个类似于以下定义的方法(简化以避免混淆):

public static void Register<T>(T value) where T : BaseClass, IInterface

只要我有一个定义这两个值的类实例,这就可以正常工作。当我将`BaseClass'传递给方法然后尝试在上面的声明中使用该实例时,会出现问题。例如:

public class MyClass
{
    public MyClass(BaseClass value)
    {
        Register(value);
    }
}

我可以将实现BaseClass和IInterface的类的实例和实例传递给构造函数,但是当我尝试在Register方法中使用该值时,我得到一个编译错误说明:

  

类型'BaseClass'不能在泛型类型或方法'Register(T)'中用作类型参数'T'。没有从'BaseClass'到'IInterface'的隐式引用转换。

如果我像这样更改构造函数中的类型:

public class MyClass
{
    public MyClass(IInterface value)
    {
        Register(value);
    }
}

我收到错误声明:

  

类型'IInterface'不能用作泛型类型或方法'Register(T)'中的类型参数'T'。没有从“IInterface”到“BaseClass”的隐式引用转换。

这看起来有点像22。 有没有办法可以定义参数来表明它必须同时实现BaseClass和IInterface?

2 个答案:

答案 0 :(得分:6)

当我写这个问题时,我想出了答案,并认为我会发布它而不是删除问题。

我只需要重新定义课程:

public class MyClass<T> where T : BaseClass, IInterface
{
    public MyClass(T value)
    {
        Register(value);
    }
}

答案 1 :(得分:1)

Matt给出的解决方案是一个简单的答案,适用于不需要将传入的对象存储在字段或集合中的情况。如果你需要持久保存传入的对象,事情就会变得更加更多。对SomeClass<T>满足多个约束的T来说,存储类T的项并将它们作为泛型传递给具有此类约束的例程,但是如果类具有方法{{1}则很容易}} SomeMethod<TParam>(TParam thing),它不会有TParam:IFoo,BaseBar类型的任何字段。它可以将TParam存储到thingIFoo类型的字段中,但除非BaseBar实现BaseBar,否则所有传入的实例都将从实现IFoo的一个特定BaseBar衍生物,没有办法指定字段的类型将满足两个约束(如果每个实例都派生自一个特定的IFoo实现BaseBar的导数,可以简单地将该类型用作单个约束,或者根本不用泛型 - 只需将其用作参数类型)。

有很多方法可以解决这些问题,使用Reflection,我称之为IFoo的接口模式,或者一些棘手的嵌套回调接口。但是,在某些情况下,最好为采用双约束参数的方法提供替代方法(让方法采用一种约束类型的参数,将其转换为另一种类型,并接受缺乏编译时的安全性)