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...