这个参数类型约束是什么意思?

She*_*per 20 c#

我正在查看一些代码,我不明白特定约束在以下类定义中的含义:

internal abstract class Entity<T> : Entity
    where T : Entity<T>
{ ... }
Run Code Online (Sandbox Code Playgroud)

我不明白这意味着参数类型T.

Mat*_*son 20

这类似于" 奇怪的重复模板模式 "(但它不一样).

它可以用于(除其他外)以帮助将派生类中的方法的参数类型约束为与派生类本身相同的类型.

这是Eric Lippert关于这个主题的一篇有趣的博客文章.

这个的主要用途是强制派生的类Entity<T>来实现一些接受与派生类相同类型的参数的方法.

在下面的代码示例中,我们在Entity<T>类中声明了一个DoSomethingWithTheSameTypeAsMe()接受类型参数的方法T.

由于泛型约束,这将强制从中派生的任何类Entity<T>实现其版本DoSomethingWithTheSameTypeAsMe()采用派生类类型的参数.

这是有限的使用,阅读非常混乱,所以我同意Eric Lippert,他说你应该避免这样的代码!

using System;

namespace ConsoleApplication1
{
    internal class Program
    {
        private static void Main()
        {
            var test1 = new Derived1();
            var test2 = new Derived2();

            test1.DoSomethingWithTheSameTypeAsMe(test1);
            test2.DoSomethingWithTheSameTypeAsMe(test2);
        }
    }

    public class Entity
    {
        public string Hello()
        {
            return "Hello, World.";
        }
    }

    public abstract class Entity<T>: Entity where T: Entity<T>
    {
        public abstract void DoSomethingWithTheSameTypeAsMe(T item);
    }

    public sealed class Derived1: Entity<Derived1>
    {
        // You are forced to implement DoSomethingWithTheSameTypeAsMe() with a param type "Derived1".
        // (i.e. the parameter is the same type as 'this')

        public override void DoSomethingWithTheSameTypeAsMe(Derived1 item)
        {
            Console.WriteLine("Doing something with a Derived1 item: " + item.Hello());
        }
    }

    public sealed class Derived2: Entity<Derived2>
    {
        public override void DoSomethingWithTheSameTypeAsMe(Derived2 item)
        {
            Console.WriteLine("Doing something with a Derived2 item: " + item.Hello());
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 对不起,你不要把C++模板和C#泛型混淆吗? (4认同)
  • 我同意,这个答案是不正确的.在CRTP中,基类也是通用的,这不是这里的情况.如果你说`Base <Derived>`和`Entity <T>`在这里相同,你也是不正确的,因为在C#中你无法以这种方式访问​​派生类的成员. (4认同)

Ada*_*rth 12

虽然我评论说,但我要坚持我的桨,因为我还要注意基本类型从中得到什么.

简单地说:T必须继承Entity<T>.

它是一种经常使用的自引用泛型,使得基类可以在方法和其他区域中包含派生类类型(via T).它简单地避免了您必须在派生类型中转换内容或使用基本引用.虽然我很少在代码中看到它,但它非常有用.

我会注意到,这并不能意味着基类可突然访问派生成员.它仍然只能看到约束定义的最低已知类型(如果存在).如果不存在约束,object则是已知最低的类型.好处是从派生类型的角度以及它对推入基类的代码授予的清洁度.

在你的情况下,它会看到Entity<T>Entity成员.这就是限制的原因.

标准用法如下:

public class Customer : Entity<Customer>
{
}

public abstract class Entity<T> 
    where T : Entity<T>
{
    public T Clone(T entityToClone)
    {
        return default(T); // Clone code here, returns derived type.
    }
}   


// Grants you...
Customer clonedCustomer = currentCustomer.Clone();

// Instead of...
Customer clonedCustomer = (Customer)currentCustomer.Clone();

// Ignore ethical constraints on cloning customers and definitely do not tell your sales team that you can ;-)
Run Code Online (Sandbox Code Playgroud)