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

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

有没有办法限制T实现接口的类型?(Foo在这种情况下)。最好强制执行任何实现ICloneable以返回其自身的实例,而不是它喜欢的任何随机类型。

4

2 回答 2

5

不,基本上。你不能用通用约束来做到这一点。此外,您不能阻止他们以不同的方式多次实现接口T(只要T满足任何where约束,在这种情况下没有约束)。

没有where允许限制实现类型的约束。

您有点可以将其作为方法参数限制来执行,但这并不令人满意:

public static T SuperClone<T>(this T original) where T : ICloneable<T> {...}
于 2014-06-23T09:50:59.323 回答
0

请注意,可以使用代码合同来表达这一点。通常这是在运行时检查的,但可能会收到编译时警告(请参阅后面的注释):

它是这样的:

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

然后,如果您有以下类定义:

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

这将在运行时正常工作:

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

这些将导致运行时代码契约失败:

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

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

请注意,您可以获得编译时警告。

如果您执行完整的代码合同静态检查编译,您Clone()看到有关forclass BadFoo和的实现“确保未经证实”的警告class AlsoBad

GoodFoo.Clone()由于Contract.Assume(result.GetType() == this.GetType());在其实施中没有警告。

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

于 2014-06-23T11:11:35.317 回答