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

本文关键字:派生 泛型 案例 实现 | 更新日期: 2023-09-27 17:55:38

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

假设我有一个泛型类:

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

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

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

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

缺点似乎是"价值"必须是公共的或内部的。

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

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

在许多情况下,可以通过约束以对类型有意义的方式使用类型的值。例如,如果使用where T : IComparable<T>约束T,则可以使用 Compare 比较任意两个T值。不幸的是,没有办法以这种方式表示算术运算符,尽管你可能想看看Marc Gravell在MiscUtil中的泛型运算符工作。

虽然我能感受到你的痛苦,但 .NET 泛型中根本没有这样的东西 - 你会想出你真正想要解决的任何问题的替代设计。

在这种情况下:

class Generic<float>
{
    // This doesn't work
    public void Add()
    {
        value + 1.0f;
    }
}
这并不意味着您正在使用使用 float 作为其泛型类型的泛型

类,但这意味着泛型类型的名称在源中是"float"(而不是使用 T,而是使用"float"作为其名称)因此没有转换为浮点型。换句话说,您将通用表示法用作模板,以后可以用实际类型替换(但不是在模板本身中,这就是为什么在C++它们被称为模板)

在此代码中:

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

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

型类型用于算术可重用性。也就是说,您必须在代码中所有可能的 T 之间编写一些共同的东西。

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是有效的。

我也在寻找类似的解决方案,我想你也从 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# 或其他托管语言中工作,但也许此解决方法可以为您提供真正想要获得的内容。