c#泛型方法和列表
我想了解为什么下面的代码不起作用,以及如何修复它 如果T是双倍或长的,为什么T不接受双倍或长的铸件c#泛型方法和列表,c#,generics,C#,Generics,我想了解为什么下面的代码不起作用,以及如何修复它 如果T是双倍或长的,为什么T不接受双倍或长的铸件 private IList<T> GetGenericList<T>(bool isDouble) where T : double, long { IList<T> Result = new List<T>(); if (isDouble) { T Value
private IList<T> GetGenericList<T>(bool isDouble) where T : double, long
{
IList<T> Result = new List<T>();
if (isDouble)
{
T Value = 2.5; // does not compile
Result.Add(Value);
}
else
{
T Value = 2; // does not compile
Result.Add(Value);
}
return Result;
}
private IList GetGenericList(bool isDouble),其中T:double,long
{
IList结果=新列表();
if(isDouble)
{
T值=2.5;//不编译
结果:增加(价值);
}
其他的
{
T值=2;//不编译
结果:增加(价值);
}
返回结果;
}
[更新]
好了,大家不要紧张!让我明白你说的话!:)
c#中泛型的原理是什么
如果我将de代码更改为以下示例?(开箱即用,这只是一个例子,请忽略de规则(if(isDouble),无论什么)
private IList GetGenericList(//参数的任何内容。。。
)其中T:double
{
IList结果=新列表();
T值=2.5;//不编译
结果:增加(价值);
返回结果;
}
谢谢,isDouble在运行时被赋予一个值。无论分支如何,这两个赋值在编译时都必须有意义
您正在尝试使用泛型执行一些原则上无法执行的操作。代码无法工作的原因有三个:
double
和long
,这是不可能的double
和long
不能用作常规约束,因为它们是密封的double
到未知类型的隐式转换对象
:
if (isDouble)
{
T Value = (T)(object)2.5; // does not compile
Result.Add(Value);
}
else
{
T Value = (T)(object)2; // does not compile
Result.Add(Value);
}
无法让方法完全按照您希望的方式工作,因为无法将T
约束为double
或long
。您可以使用反射检查类型,如果不是其中之一,则抛出异常,但无法在编译时强制执行
核心问题是您的代码不是泛型的。真正的泛型代码不关心T
是什么(对一些非常广泛的参数进行模化,比如它必须实现一些接口)。调用者需要确定什么是T
,而不是方法,因此根据T
的实际类型具有不同逻辑的任何东西通常都是代码气味。这似乎只是一个学习练习,但如果您在现实生活中需要此功能,我建议使用两种不同的方法:
private IList<double> GetDoubleList()
{
IList<double> Result = new List<double>();
double Value = 2.5;
Result.Add(Value);
return Result;
}
private IList<long> GetLongList()
{
IList<long> Result = new List<long>();
long Value = 2;
Result.Add(Value);
return Result;
}
private IList GetDoubleList()
{
IList结果=新列表();
双值=2.5;
结果:增加(价值);
返回结果;
}
私有IList GetLongList()
{
IList结果=新列表();
长值=2;
结果:增加(价值);
返回结果;
}
它并不比你开始时长多少,有一点重复,但不多,它是完全类型安全的,并且在方法中没有类型歧义
接下来,您可以将冗余代码重构为泛型方法(在这种情况下,您不需要约束它,因为您可以从调用方法控制类型):
private IList GetList(T值)
{
IList结果=新列表();
结果:增加(价值);
返回结果;
}
私有IList GetDoubleList()
{
返回GetList(2.5);
}
私有IList GetLongList()
{
返回GetList(2);
}
要回答您的问题,请参阅:
对于您当前只希望处理double
或long
的问题,您可以按照D Stanley的建议,只需处理其他类型的问题。以下是一个示例:
private IList<T> GetGenericList<T>()
{
Type parmType = typeof(T);
if (!parmType.Equals(typeof(double)) && !parmType.Equals(typeof(long)))
{
return null;
}
else
{
IList<T> Result = new List<T>();
if (parmType.Equals(typeof(double)))
{
T Value = (T)(object)2.5;
Result.Add(Value);
}
else
{
T Value = (T)(object)2L;
Result.Add(Value);
}
return Result;
}
}
private IList GetGenericList()
{
类型parmType=类型(T);
如果(!parmType.Equals(typeof(double))&&!parmType.Equals(typeof(long)))
{
返回null;
}
其他的
{
IList结果=新列表();
if(parmType.Equals(typeof(double)))
{
T值=(T)(对象)2.5;
结果:增加(价值);
}
其他的
{
T值=(T)(对象)2L;
结果:增加(价值);
}
返回结果;
}
}
现在,当我这样使用它时:
List<double> lDbl = (List<double>)GetGenericList<double>();
List<long> lLng = (List<long>)GetGenericList<long>();
List<string> lStr = (List<string>)GetGenericList<string>();
List lDbl=(List)GetGenericList();
List lLng=(List)GetGenericList();
List lStr=(List)GetGenericList();
最后我得到了
lDbl
和lLng
中的预期值,包括正确的数据类型。但是,lStr
被设置为null
,因为这是我让它处理除double
或long
之外的类型的方式。你可以很容易地在其中抛出一个异常。你没有理由这么做需要提供isDouble作为参数;T的类型可以在运行时确定:type-typeParameterType=typeof(T)
:double,long
意思是double和long,也就是说,这是无稽之谈。我印象深刻的是,这甚至会compile@Jonesopolis它没有编译;首先:@Blorgbeard不,它没有。OP给人的印象是它编译了。我很笨。真正奇怪的是,我得到了一个带有t Value=(t)(object)的InvalidCastException2、
。我处理它的方法是使用T Value=(T)(object)2L;
这是因为实际类型是int
,因为它是整数文本。因为引用强制转换要求实际类型是兼容的(而不是可转换的)强制转换将在运行时失败。这是我在事后检查它时所想到的。我同意您的编辑,尤其是接受任何值的最终重构。在泛型方法中进行检查会失败。我也同意这似乎是一个学习练习。将中心思想保留在一个方法中是一个很好的示例。这就是我一直在看的…谢谢!!谢谢克里斯和所有人!演员阵容怎么样了?List lDbl=GetGenericList();
应该没问题,对吧
private IList<T> GetGenericList<T>()
{
Type parmType = typeof(T);
if (!parmType.Equals(typeof(double)) && !parmType.Equals(typeof(long)))
{
return null;
}
else
{
IList<T> Result = new List<T>();
if (parmType.Equals(typeof(double)))
{
T Value = (T)(object)2.5;
Result.Add(Value);
}
else
{
T Value = (T)(object)2L;
Result.Add(Value);
}
return Result;
}
}
List<double> lDbl = (List<double>)GetGenericList<double>();
List<long> lLng = (List<long>)GetGenericList<long>();
List<string> lStr = (List<string>)GetGenericList<string>();