有没有办法将通用接口约束到实现它的类型?

时间:2014-06-23 09:46:49

标签: c# generics interface generic-constraints

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

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

有没有办法将T约束到实现接口的类型? (在这种情况下为Foo)。最好强制执行任何实现ICloneable的任何东西来返回它自己的实例,而不是它想要的任何随机类型。

2 个答案:

答案 0 :(得分:5)

不,基本上。你不能用通用约束来做到这一点。此外,您无法阻止他们使用不同的T多次实现该界面(只要那些T满足任何where约束,在这种情况下都不会。)

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

你有点可以做一个方法参数限制,但它并不是真的令人满意:

public static T SuperClone<T>(this T original) where T : ICloneable<T> {...}

答案 1 :(得分: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();

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

如果您执行完整的代码合同静态检查编译,您看到关于&#34的警告;确保未经证实&#34;用于Clone()class BadFoo的{​​{1}}的实现。

class AlsoBad没有警告,因为其实施中有GoodFoo.Clone()

但是,代码合同静态检查(在我看来)对于除偶尔检查之外的任何事情来说仍然太慢,但您的里程可能会有所不同......