简体   繁体   English

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

[英]Implementing a specific case of a generic, versus deriving from it

I am trying to write out a specific case of a generic class with additional functionality, but I am not sure why the following happens. 我试图写出具有附加功能的泛型类的特定情况,但我不确定为什么会发生以下情况。

Suppose I have a generic class: 假设我有一个泛型类:

class Generic<T>
{
   protected T value;
}

If I write out a specific implementation, I can't actually use the specific type I've narrowed it down to: 如果我写出一个特定的实现,我实际上无法使用我将其缩小到的特定类型:

EDIT: I goofed up, this doesn't work. 编辑:我搞砸了,这不起作用。

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

But if I inherit from the specific version, it does work: 但是,如果我从特定版本继承,它确实有效:

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

In case someone is still reading this, I wanted to point out that this seems to be possible with extension methods: 如果有人还在读这个,我想指出这似乎可以通过扩展方法:

class Generic<T>
{
    public T value;
}

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

The downside seems to be that 'value' has to be public or internal. 缺点似乎是“价值”必须是公开的或内部的。

I also looked for similar solution, I think you also got this thinking from ADA or such programming language. 我也寻找类似的解决方案,我想你也从ADA或这样的编程语言中得到了这个想法。 But, as others wrote, making type specific class definition is not generic programming, it's specialization, so the simpliest (and only in C#) way is to create a specified class, based on generic structure: 但是,正如其他人写的那样,使类型特定的类定义不是泛型编程,它是专门化的,所以最简单的(并且只在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;
    }
}

As you can see, we created a class for the specified case, having the extra ability of extending the structure with fields and methods. 如您所见,我们为指定的案例创建了一个类,具有使用字段和方法扩展结构的额外功能。 This advantage is very good to refine behavior of our objects, and gives ability of implicit cast of the typed generic class to our customized one (with the notice that casting back is not possible): 这个优点非常适合细化我们对象的行为,并且能够将类型化泛型类隐式强制转换为我们的自定义类(注意不能返回):

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
}

Don't know if the way you expected should work in languages like C# or other managed ones, but maybe this workaround gives you what you really wanted to get. 不知道你期望的方式是否应该像C#或其他托管类似的语言一样工作,但也许这种解决方法可以为你提供你真正想要的东西。

Your first attempt simply isn't a valid declaration - the part that specifies a class can't specify any type arguments. 您的第一次尝试根本不是有效声明 - 指定类的部分不能指定任何类型参数。

If you think about it, how would the CLR know whether or not there was a specialized type available? 如果您考虑一下,CLR将如何知道是否有可用的专用类型? What would it do if there were two different specializations of the same generic type in two loaded assemblies? 如果在两个加载的程序集中存在两个相同泛型类型的不同特化,它会怎么做? It would have to check all the referenced assemblies any time a particular type argument combination was used for the first time. 每当第一次使用特定类型的参数组合时,它必须检查所有引用的程序集。 (This couldn't be done at compile-time, as other classes may just be referring to Generic<T> .) (这不能在编译时完成,因为其他类可能只是指Generic<T> 。)

In many cases you can use values of the type in ways which are meaningful to the type using constraints. 在许多情况下,您可以使用对使用约束的类型有意义的方式使用类型的值。 For example, if you constrain T with where T : IComparable<T> then you can compare any two T values using Compare . 例如,如果将T约束where T : IComparable<T>则可以使用Compare比较任意两个T值。 Unfortunately there's no way of representing arithmetic operators in this way, although you may want to look at Marc Gravell's generic operator work in MiscUtil . 不幸的是,没有办法用这种方式表示算术运算符,尽管你可能想看看Marc Gravell在MiscUtil中的泛型运算符

While I feel your pain, there's simply nothing like this in .NET generics - you'll want to think of alternative designs for whatever problem you're really trying to solve. 虽然我感觉到你的痛苦,但在.NET泛型中却没有这样的东西 - 你会想要为你真正试图解决的任何问题考虑替代设计。

in this case : 在这种情况下 :

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

It doesn't mean that you are working with a Generic class using float as its generic type but it means that the name of the generic type is "float" in the source (instead of using T you are using "float" as its name ) Thus there's no conversion to float.In other words you are using a generic notation as a template that can be substituted with real types later (but not in the template itself and that's why in C++ they are called templates) 这并不意味着您正在使用一个使用float作为其泛型类型的Generic类,但这意味着泛型类型的名称在源代码中是“float”(而不是使用T,您使用“float”作为其名称因此,没有转换为float。换句话说,您使用通用符号作为模板,以后可以用实际类型替换(但不是在模板本身,这就是为什么在C ++中它们被称为模板)

In this code : 在这段代码中:

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

you are telling the compiler that you want the specific class be a child of a generic class while it's template type will be replaced by type float. 您告诉编译器您希望特定类是泛型类的子类,而它的模板类型将替换为float类型。

Generic types are used for arithmetic reusability. 通用类型用于算术可重用性。 That is, you must write something common between all possible Ts in your code. 也就是说,你必须在代码中的所有可能的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
   }
}

And when you specified some T (eg float in your question), the compiler knows the T is float, so it's valid to add 0.1f to it. 当你指定一些T(例如你的问题浮点数)时,编译器知道T是浮点数,所以向它添加0.1f是有效的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM