c#泛型方法和List
本文关键字:List 泛型方法 | 更新日期: 2025-03-17 18:23:32
我想了解为什么下面的代码不起作用以及如何修复它。
如果T是双或长,为什么T不接受双或长的铸造?
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;
}
[更新]好吧,人们不要紧张!让我理解你说的话!:)
c中泛型的原理是什么?
如果我将代码更改为以下示例?(开箱即用,这只是一个例子,请忽略规则(如果(isDouble),不管怎样)
private IList<T> GetGenericList<T>(//whatever you want of param...
) where T : double
{
IList<T> Result = new List<T>();
T Value = 2.5; // does not compile
Result.Add(Value);
return Result;
}
感谢
您的代码无法工作的原因有三个:
- 泛型约束要求类型同时继承
double
和long
,这是不可能的 - CCD_ 3和CCD_ 4不能用作通用约束,因为它们是密封的
- 没有从
double
到未知类型的隐式转换
前两个没有"修复"。最后一个的修复方法是先转换为object
:
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<T> GetList<T>(T Value)
{
IList<T> Result = new List<T>();
Result.Add(Value);
return Result;
}
private IList<double> GetDoubleList()
{
return GetList<double>(2.5);
}
private IList<long> GetLongList()
{
return GetList<long>(2);
}
isDouble在运行时被赋予一个值。无论分支如何,这两个赋值在编译时都必须有意义。
你试图用泛型做一些原则上做不到的事情。
要回答您的答案,请参阅:泛型简介(C#编程指南)
就您当前的问题而言,您只希望处理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;
}
}
现在,当我这样使用它时:
List<double> lDbl = (List<double>)GetGenericList<double>();
List<long> lLng = (List<long>)GetGenericList<long>();
List<string> lStr = (List<string>)GetGenericList<string>();
最后我得到了lDbl
和lLng
中的预期值,包括正确的数据类型。但是,lStr
被设置为null
,因为这就是我让它处理除double
或long
之外的类型的方式。你可以很容易地抛出一个异常。