C#泛型约束:接口

时间:2014-07-02 11:18:44

标签: c# generics interface where

我对一些代码提出了一个问题:

interface IDistance<T> 
{
        double distance();
        double distance(T obj);
}

class Point<T> where T : IDistance<T>  //why do i need this?
{
        T obj;
        public double dist(T val) { return obj.distance(val); 
        public Point(T obj) { this.obj = obj; }
}

class P2D : IDistance<P2D>
{
        public double[] x = new double[2];

        public P2D(double x, double y)
        {
            this.x[0] = x; this.x[1] = y;
        }

        public double distance()
        {
            double d = 0.0;
            for (int i = 0; i < 2; i++) d = d + x[i] * x[i];
            return Math.Sqrt(d);
        }

        public double distance(P2D val)
        {
           double d = 0.0;
           for (int i = 0; i < 2; i++) d = d + Math.Pow(x[i]-val.x[i],2);
           return Math.Sqrt(d);
        }
}

class Tester
{
        static void Main(string[] args)
        {
            P2D P1 = new P2D(3.0, 4.0);
            Point<P2D> C1 = new Point<P2D>(P1);
            Console.WriteLine(C1.dist());
        }
} 

详细的代码并不重要。

为什么我需要通用类where T : IDistance<T>中的约束Point<T>

当我只指定已实现接口IDistance<T>的类时 P2D类不应该是类Point中隐含的已经实现的接口吗?

我认为当类<T>中的类Point定义为未实现接口时,它可能会导致问题。但在这种情况下,为什么不可能呢?

4 个答案:

答案 0 :(得分:2)

Point<T>中查看此代码:

T obj;
public double dist(T val) { return obj.distance(val); 

当编译器试图理解这个表达式的含义时:

obj.distance(val)

必须解析distance成员。如果T不受约束,则不能这样做。当T被限制为实现IDistance<T>时,它可以 - 它将其解析为接口的成员。

特别是,没有约束,我可以用很奇怪的方式使用这个类型:

Point<string> weird = new Point<string>("foo");
double result = weird.dist("bar");

你期望做什么?

(作为旁注,值得遵循正常的.NET命名约定,即使是示例。方法应该是PascalCased,我永远不会调用类P2D ...)

答案 1 :(得分:1)

  

为什么我需要这个?

您需要约束,因为您将通用类型限制为接口IDistance<T>的实现。如果Point类使用此类型的某些方法,例如obj.distance(val);

您还可以使用抽象类来限制派生。看看MSDN中的文档。 http://msdn.microsoft.com/en-us/library/bb384067.aspx

答案 2 :(得分:1)

  

当我只指定已经实现了类P2D之类的接口IDistance的类时,不应该是已经在Class Point中隐式实现的接口吗?当定义类Point中的类没有实现接口时,我会发现它可能导致问题。但在这种情况下,为什么不可能呢?

因为C#是一种具有编译时类型安全性的语言。如果没有该约束,您可能只在运行时使用Point<T>实例化T来实现IDistance<T>,但编译器无法在编译时知道您将如此乖巧。

答案 3 :(得分:0)

class Point<T> where T : IDistance<T>  //why do i need this?

你需要这个,因为你声明的类应该是一个实现名为IDistance<T>的接口的类型