Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I return a more derived type from an interface?

I have an interface that transforms a grid of data which I want to implement:

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);
}

So I make a class that does so:

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

However, when making a more derived version of mesh, I run into an issue. For example, I have a Heightmap class which is a Mesh<float>. By making a specific implementation of T, this allows me to use operator overloads so I can add easily add two heightmaps together, for example. But when I implement it

public class Heightmap : Mesh<float> { ... }

Heightmap's functions from ITransformable still return a Mesh, rather than a Heightmap. Is there any way to implement a base behavior in Mesh, but "change" the return type in the more derived class? I thought this was the purpose of covariance, but I can't seem to figure it out.

like image 567
Kyle Baran Avatar asked Feb 01 '26 17:02

Kyle Baran


1 Answers

Please try the following code, it should work like charm. Replace the Methods/Exception to your own implementation.

  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.
        }
    }
like image 65
Kajal Sinha Avatar answered Feb 03 '26 09:02

Kajal Sinha