c#泛型方法和列表

时间:2016-05-11 20:13:08

标签: c# generics

我想了解为什么下面的代码不起作用以及如何修复它。

如果T为double或long为什么T不接受double或long的转换?

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

[UPDATE] 好的人不要紧张!让我明白你说的话! :)

c#中泛型的原理是什么?

如果我将de代码更改为以下示例? (开箱即用,这只是一个例子,请忽略de规则(if(isDouble),等等)

apt-get update
apt-get install -y python-software-properties
add-apt-repository -y ppa:ondrej/php
add-apt-repository -y ppa:ondrej/apache2
apt-get update
apt-get upgrade -y

apt-get install -y htop apache2 php5.6 php5.6-curl php5.6-mcrypt mongodb-org curl git

由于

3 个答案:

答案 0 :(得分:1)

您的代码无效的原因有三个:

  1. 您的通用约束要求该类型继承doublelong,这是不可能的
  2. doublelong不能用作通用约束,因为它们是密封的。
  3. 没有从double隐式转换为未知类型
  4. 前两个没有“修复”。最后一个的修复方法是首先转换为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或{{1} }。您可以使用反射检查类型,如果它不是其中之一则抛出异常,但是在编译时无法强制执行该异常。

    核心问题是您的代码不是通用的。真正的通用代码并不关心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;
    }
    

答案 1 :(得分:0)

isDouble在运行时被赋予一个值。无论分支如何,这两个赋值在编译时都必须有意义。

您正在尝试使用原则上无法完成的泛型。

答案 2 :(得分:0)

要回答您的回答,请参阅:Introduction to Generics (C# Programming Guide)

就目前您只想处理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以外的类型的方式。您可以轻松地在那里抛出异常。