如何从界面返回更多派生类型?

时间:2014-06-27 00:23:09

标签: c# generics interface covariance

我有一个界面来转换我想要实现的数据网格:

public interface ITransformable<T>
{
    T Slice(int x, int y, int width, int height);
    T Slice(Rectangle value);
    T Transpose();
    T Flip(bool horizontal, bool vertical);
    T Rotate(bool clockwise);
}

所以我创建了一个这样做的课程:

public class Mesh<T> : ITransformable<Mesh<T>>
{
    public Mesh<T> Transpose() { ... }
    /// etc
}

但是,在制作更多衍生版本的网格时,我遇到了一个问题。例如,我有一个Heightmap类,它是Mesh<float>。通过进行T的特定实现,这允许我使用运算符重载,因此我可以轻松添加两个高度图,例如。但是当我实施它时

public class Heightmap : Mesh<float> { ... }
来自ITransformable的

Heightmap函数仍然返回一个Mesh,而不是Heightmap。有没有办法在Mesh中实现基本行为,但是“更改”更多派生类中的返回类型?我认为这是协方差的目的,但我似乎无法弄明白。

1 个答案:

答案 0 :(得分:1)

请尝试以下代码,它应该像魅力一样工作。将Methods / Exception替换为您自己的实现。

  public interface ITransformable<T, out S> where S : ITransformable<T, S>
    {
        S Slice(int x, int y, int width, int height);
        S Slice(Rectangle value);
        S Transpose();
        S Flip(bool horizontal, bool vertical);
        S Rotate(bool clockwise);
    }

    public class Mesh<T, S> : ITransformable<T, S> where S : Mesh<T,S>, ITransformable<T, S>, new()
    {
        public S Slice(int x, int y, int width, int height)
        {
            throw new NotImplementedException();
        }

        public S Slice(Rectangle value)
        {
            throw new NotImplementedException();
        }

        public S Transpose()
        {
           //The following will work smoothly.
           S sObject = this.Slice(10, 20, 30, 40);
           return sObject;
        }
        public S Flip(bool horizontal, bool vertical)
        {
            throw new NotImplementedException();
        }

        public S Rotate(bool clockwise)
        {
            throw new NotImplementedException();
        }

    }

    public class Heightmap : Mesh<float, Heightmap>
    {

    }

    public class Program
    {
        static void Main()
        {
            Heightmap heightmap = new Heightmap();
            Heightmap map2 = heightmap.Transpose(); //This will work smoothly.
        }
    }