0
public interface ICloneable<T>
{
    T Clone();
}

public Foo: ICloneable<Foo>
{
    public Foo Clone()
    { 
       //blah
    }
}

Is there any way to constrain T to the type that implements the interface? (Foo in this case). It would be nice to enforce anything implementing ICloneable to return an instance of itself, and not any random type it fancies.

GazTheDestroyer
  • 20,722
  • 9
  • 70
  • 103

2 Answers2

5

No, basically. You can't do that with generic constraints. Also, you can't stop them implementing the interface multiple times with different T (as long as those T satisfy any where constraints, none in this case).

There is no where constraint that allows restriction to the implementing type.

You kinda sorta can do it as a method parameter restriction, but it isn't really satisfactory:

public static T SuperClone<T>(this T original) where T : ICloneable<T> {...}
Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • @AlessandroD'Andria I believe you are mistaken. See also http://blogs.msdn.com/b/ericlippert/archive/2011/02/03/curiouser-and-curiouser.aspx – Kris Vandermotten Jun 23 '14 at 10:10
0

Note that it is possible to use Code Contracts to express this. Normally this is checked at runtime but it's possible to get a compile-time warning (see the notes later):

It goes something like this:

[ContractClass(typeof(CloneableContract<>))]

public interface ICloneable<out T>
{
    T Clone();
}

[ContractClassFor(typeof(ICloneable<>))]

internal abstract class CloneableContract<T>: ICloneable<T>
{
    public T Clone()
    {
        Contract.Ensures(Contract.Result<object>() != null);
        Contract.Ensures(Contract.Result<object>().GetType() == this.GetType());

        return default(T);
    }
}

Then if you have the following class definitions:

public class GoodFoo: ICloneable<GoodFoo>
{
    public virtual GoodFoo Clone()
    { 
        var result = new GoodFoo();
        Contract.Assume(result.GetType() == this.GetType());
        return result;
    }
}

public class BadFoo: ICloneable<object>
{
    public object Clone()
    {
        return new object(); // warning : CodeContracts: ensures unproven: Contract.Result<object>().GetType() == this.GetType()
    }
}

public class AlsoBad: GoodFoo
{
    public override GoodFoo Clone()
    {
        return new GoodFoo(); // warning : CodeContracts: ensures unproven: Contract.Result<object>().GetType() == this.GetType()
    }
}

This will work OK at runtime:

var good = new GoodFoo();
good.Clone();

These will cause runtime Code Contract failures:

var bad = new BadFoo();
bad.Clone();

var alsoBad = new BadFoo();
alsoBad.Clone();

Note that you can get a compile time time warning.

If you do a full Code Contracts Static Checking compile, you will see warnings about "ensures unproven" for the implementations of Clone() for class BadFoo and class AlsoBad.

There is no warning for GoodFoo.Clone() because of the Contract.Assume(result.GetType() == this.GetType()); in its implementation.

However, Code Contracts Static Checking is (in my opinion) still too slow for anything but occasional checking, but your mileage may vary...

Matthew Watson
  • 104,400
  • 10
  • 158
  • 276