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;
}

感谢

c#泛型方法和List

您的代码无法工作的原因有三个:

  1. 泛型约束要求类型同时继承doublelong,这是不可能的
  2. CCD_ 3和CCD_ 4不能用作通用约束,因为它们是密封的
  3. 没有从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约束为doublelong可以使用反射检查类型,如果它不是其中之一,则抛出异常,但在编译时无法强制执行。

核心问题是您的代码不是通用的。真正的泛型代码并不关心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#编程指南)

就您当前的问题而言,您只希望处理doublelong,您可以按照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>();

最后我得到了lDbllLng中的预期值,包括正确的数据类型。但是,lStr被设置为null,因为这就是我让它处理除doublelong之外的类型的方式。你可以很容易地抛出一个异常。