实现泛型的特定案例,而不是从中派生

时间:2011-05-10 06:20:56

标签: c# generics

我正在尝试写出具有附加功能的泛型类的特定情况,但我不确定为什么会发生以下情况。

假设我有一个泛型类:

class Generic<T>
{
   protected T value;
}

如果我写出一个特定的实现,我实际上无法使用我将其缩小到的特定类型:

编辑:我搞砸了,这不起作用。

class Generic<float>
{
    // This doesn't work
    public void Add()
    {
        value + 1.0f;
    }
}

但如果我从特定版本继承,它确实有效:

class Specific : Generic<float>
{
    // This does work
    public void Add()
    {
        value + 1.0f;
    }
}

5 个答案:

答案 0 :(得分:4)

如果有人还在读这篇文章,我想指出这似乎可以通过扩展方法实现:

class Generic<T>
{
    public T value;
}

static class Extension
{
    public static void Add (this Generic<float> generic)
    {
        generic.value += 1.0f;
    }
}

缺点似乎是&#39;价值&#39;必须是公开的或内部的。

答案 1 :(得分:0)

您的第一次尝试根本不是有效声明 - 指定类的部分不能指定任何类型参数。

如果您考虑一下,CLR将如何知道是否有可用的专用类型?如果在两个加载的程序集中存在两个相同泛型类型的不同特化,它会怎么做?每当第一次使用特定类型的参数组合时,它必须检查所有引用的程序集。 (这不能在编译时完成,因为其他类可能只是指Generic<T>。)

在许多情况下,可以使用类型的值,这些方式对使用约束的类型有意义。例如,如果您使用T约束where T : IComparable<T>,则可以使用T比较任意两个Compare值。遗憾的是,虽然您可能希望查看Marc Gravell's generic operator work in MiscUtil,但无法以这种方式表示算术运算符。

虽然我感觉到你的痛苦,但在.NET泛型中却没有这样的东西 - 你会想到你正在努力解决的任何问题的替代设计。

答案 2 :(得分:0)

在这种情况下:

class Generic<float>
{
    // This doesn't work
    public void Add()
    {
        value + 1.0f;
    }
}

这并不意味着您使用float作为泛型类型使用Generic类,但这意味着泛型类型的名称在源代码中是“float”(而不是使用T,您使用的是“float”因此,它没有转换为float。换句话说,你使用通用符号作为模板,以后可以用真实类型替换(但不是在模板本身,这就是为什么在C ++中它们被称为模板)

在此代码中:

    class Specific : Generic<float>
{
    // This does work
    public void Add()
    {
        value + 1.0f;
    }
}

你告诉编译器你希望特定的类是泛型类的子类,而它的模板类型将被float类型替换。

答案 3 :(得分:0)

通用类型用于算术可重用性。也就是说,你必须在代码中的所有可能的Ts之间写一些共同点。

class Generic<T>
{
   protected T value;   //it's valid to declare a member whose type is T
   public void Add()
   {
      value + 1.0f;   //invalid, because not all T are allowed to add 
                      //with 0.1f by default
                      //consider T is the type Person
   }

   public void Print()
   {
      Type t = typeof(T);   //valid, for all T we can get its type
   }
}

当你指定一些T(例如你的问题浮点数)时,编译器知道T是浮点数,所以向它添加0.1f是有效的。

答案 4 :(得分:0)

我也寻找类似的解决方案,我想你也从ADA或这样的编程语言中得到了这个想法。 但是,正如其他人所写,使类型特定的类定义不是泛型编程,它是专业化的,所以最简单的(并且只有在C#中)方法是基于通用结构创建指定的类:

class Generic<T>
{
    protected T value;
    public Generic(T val)
    {
        value = val;
    }
}

class Generic_float : Generic<float>
{
    public Generic_float(float val)
        : base(val)
    {
    }
    public void Add()
    {
        value = value + 1.0f;
    }
}

如您所见,我们为指定的案例创建了一个类,具有使用字段和方法扩展结构的额外功能。这个优点非常适合细化我们对象的行为,并且能够将类型化泛型类隐式强制转换为我们自定义的类(注意不能返回):

public void Test()
{
    Generic<float> var1 = new Generic<float>(1.5f);
    Generic_float var2 = new Generic_float(2.5f);
    var1 = var2; // Works, var links to var2's memory field casted as Generic<float>
    var2 = var1; // cannot implicitly convert error, if want to use then have to make explicit conversion
}

不知道您的预期方式是否应该使用C#或其他托管语言等语言,但也许这种解决方法可以为您提供您真正想要的内容。