我在C ++中使用过模板,但过去并没有真正尝试使用C#泛型。这是我正在尝试做的简化的简化版本(这在C ++中是可能的):
DoStuff()
我收到以下编译错误(在GenericBase<T>
上的DoesStuffWithPrimatives.DoStuff(…)
方法中):
错误CS1503参数1:无法从'T'转换为'double'
为什么编译器无法解析调用哪个{{1}}重载??
答案 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
可以是任何内容,IEnumerable
,Button
,XmlSerializer
,Dictionary<int, int>
,CultureInfo
甚至是你自己创造的一些类型,仅举几个极端的类型。显然,您永远不能将CultureInfo
传递给接受double
或int
的方法。
错误信息只是编译器说T
可以是任何类型的方式,而不是double
或int
。
这个问题的解决方案之一很简单,根本就不要使用泛型!在我看来,我认为你不应该在这种情况下使用泛型。
当您不关心(或根本不关心)使用何种类型时,应使用泛型。例如,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
变量