【问题标题】:Any way to constrain a generic interface to the type that implements it?有什么方法可以将泛型接口限制为实现它的类型?
【发布时间】:2014-06-23 09:46:49
【问题描述】:
public interface ICloneable<T>
{
    T Clone();
}

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

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

【问题讨论】:

  • 当你实现ICloneable&lt;Foo&gt;时,你必须返回一个Foo或者一个派生的。我在这里错过了什么吗?
  • @YuvalItzchakov 我相信重点是Foo 可以很容易地: ICloneable&lt;Customer&gt;
  • 哦,我明白了。感谢@MarcGravell 的澄清
  • 没有。重点是什么?你能告诉我使用那个接口的代码吗?

标签: c# generics interface generic-constraints


【解决方案1】:

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

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

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

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

【讨论】:

【解决方案2】:

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

它是这样的:

[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() 的实现“确保未经证实”的警告,class BadFooclass AlsoBad

GoodFoo.Clone() 没有警告,因为在其实现中使用了 Contract.Assume(result.GetType() == this.GetType());

但是,代码合同静态检查(在我看来)仍然太慢,除了偶尔检查外,其他任何事情都无法进行,但您的里程可能会有所不同...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-01-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多