C#泛型类调用方法使用基元重载

时间:2016-12-23 02:27:05

标签: c# generics

我在C ++中使用过模板,但过去并没有真正尝试使用C#泛型。这是我正在尝试做的简化的简化版本(这在C ++中是可能的):

DoStuff()

我收到以下编译错误(在GenericBase<T>上的DoesStuffWithPrimatives.DoStuff(…)方法中):

  

错误CS1503参数1:无法从'T'转换为'double'

为什么编译器无法解析调用哪个{{1}}重载??

3 个答案:

答案 0 :(得分:1)

使用泛型,编译器可以做的最好的事情是假设类型参数(在这种情况下为T)可以是任何类型,其基数与您指定的一样。由于您没有指定基数,编译器会将T视为从Object继承的任何内容,这实际上就是任何内容。

编译器无法确定您的T是否为双,因为对于 a {{1}的每种类型的T都没有意义}}。例如,采用以下通用方法:

double

public void DoStuff<T>(T param) { DoStuffWithDouble(param); } 加倍时,这样可以正常工作,因为您可以将T替换为double

T

但是,public void DoStuff(double param) { DoStuffWithDouble(param); // param is a double, so no problem } 可能是其他内容,例如T。在这种情况下,此代码将无法编译:

List

编译器不能假设public void DoStuff(List param) { DoStuffWithDouble(param); // param is not double, this wouldn't compile } 是双倍的,因为这样做会破坏T不是双倍的地方。

当然,您可以将其强制转换,也可以对对象执行类型检查。

T

答案 1 :(得分:0)

代码不起作用的原因是T不限于一组固定的类型。 T可以是任何类型:struct,class,delegate,interface ...

执行此操作时:

public void DoStuff()
{
    _doesStuff.DoStuff(_testValue);
}

它当然不会编译,因为_testValue可以是任何内容,IEnumerableButtonXmlSerializerDictionary<int, int>CultureInfo甚至是你自己创造的一些类型,仅举几个极端的类型。显然,您永远不能将CultureInfo传递给接受doubleint的方法。

错误信息只是编译器说T可以是任何类型的方式,而不是doubleint

这个问题的解决方案之一很简单,根本就不要使用泛型!在我看来,我认为你不应该在这种情况下使用泛型。

当您不关心(或根本不关心)使用何种类型时,应使用泛型。例如,List<T>并不关心它存储的类型。它适用于任何类型。其他一些类/接口/方法使用具有特定属性的类型:实现某些接口,具有默认构造函数,是类等。这就是为什么我们有泛型类型约束。但是,始终存在满足这些约束的无限类型。您始终可以创建实现某些接口的类型或具有默认构造函数的类型。不存在将泛型类型约束为有限数量类型的泛型约束,就我所关注的“原语”而言。

答案 2 :(得分:0)

如上所述,编译器无法确切知道T是任何重载的有效类型。但是,可以使用反射来获得正确的方法。如果没有正确处理,这可能会导致运行时错误并且会产生一些开销。如果可以有一个静态变量,那么开销可以在很大程度上被否定。在下面的示例中,Action<T>'dostuffer'将在每种类型使用时确定一次:

class GenericBase<T>
{
    private readonly T _testValue;

    public GenericBase(T testValue)
    {
        _testValue = testValue;
    }


    static readonly DoesStuffWithPrimatives _doesStuff = new DoesStuffWithPrimatives();
    static readonly Action<T> dostuffer = (Action<T>)Delegate.CreateDelegate(typeof(Action<T>),_doesStuff,
        typeof(DoesStuffWithPrimatives).GetMethod(nameof(DoesStuffWithPrimatives.DoStuff), new[]{typeof(T)}));


    public void DoStuff()
    {
        dostuffer(_testValue);
    }
}

如果DoesStuffWithPrimatives类不能是静态的(如果它可以由几个不同的变量组成),则静态变量应该是方法info,而GenericBase的实例构造函数应该处理CreateDelegate,使用DoesStuffWithPrimatives变量