Covariant Collection无法正常工作

时间:2014-12-12 22:24:18

标签: c# collections covariance

很抱歉,如果问题多余,但我找不到针对我的具体案例的解决方案。 请考虑以下代码块:

public interface IPoint {}
public class GazePoint : IPoint {}
public Point AvgPoint(IEnumerable<IPoint> locations) {}

List<GazePoint> gazePoints = new List<GazePoint>();
//...
// this doesn't work:
Point avg = AvgPoint(gazePoints);

你能解释为什么它不起作用(我假设C#4.0已经解决了这个问题),我怎样才能改变AvgPoint()方法的签名,以便能够接收不同的IPoint实现。 (我不想将gazePoints集合转换为另一种类型的集合,因为它处于一个很大的循环中,我对性能感到担忧。

[更新]:我将GazePoint定义为struct,这就是问题的根源。不过,我不知道为什么struct不能在这里工作。

1 个答案:

答案 0 :(得分:0)

我不确定你遇到的确切问题是什么,但这里有什么对我有用:

首先,一些实际的类实现:

public interface IPoint
{
    int X { get; set; }
    int Y { get; set; }
}

public class Point : IPoint
{
    public int X { get; set; }
    public int Y { get; set; }

    public Point()
    {
    }

    public Point(int x, int y)
    {
        X = x;
        Y = y;
    }
}

public class GazePoint : IPoint
{
    public int X { get; set; }
    public int Y { get; set; }

    public GazePoint()
    {
    }

    public GazePoint(int x, int y)
    {
        X = x;
        Y = y;
    }
}

然后是实际的AvgPoint方法实现:

public static Point AvgPoint(IEnumerable<IPoint> locations)
{
    if (locations == null || !locations.Any()) return new Point(0, 0);

    return new Point((int) locations.Average(l => l.X), 
        (int) locations.Average(l => l.Y));
}

最后进行了一些测试:

public static void Main()
{
    var points = new List<Point>
    {
        new Point(1, 2),
        new Point(3, 4)
    };

    var gazePoints = new List<GazePoint>
    {
        new GazePoint(1, 2),
        new GazePoint(3, 4)
    };

    Point avgPoint = AvgPoint(points);
    Point avgGazePoint = AvgPoint(gazePoints);

    Console.WriteLine("Average Point = {0}, {1}", avgPoint.X, avgPoint.Y);
    Console.WriteLine("Average GazePoint = {0}, {1}", avgGazePoint.X, avgGazePoint.Y);
}

如果您的目标是让方法返回传入的相同类型的平均值,则可以将其设为通用:

public static T AvgPoint<T>(IEnumerable<T> locations) where T : IPoint, new()
{
    if (locations == null || !locations.Any()) return new T {X = 0, Y = 0};

    return new T {X = (int) locations.Average(l => l.X), 
        Y = (int) locations.Average(l => l.Y)};
}