public interface ICloneable<T>
{
T Clone();
}
public Foo: ICloneable<Foo>
{
public Foo Clone()
{
//blah
}
}
有什么办法可以将T
约束为实现接口的类型吗? (在这种情况下为Foo
)。执行ICloneable
来返回它自己的一个实例,而不是任何它幻想的随机类型将是很好的。任何将通用接口约束为实现它的类型的方法?
public interface ICloneable<T>
{
T Clone();
}
public Foo: ICloneable<Foo>
{
public Foo Clone()
{
//blah
}
}
有什么办法可以将T
约束为实现接口的类型吗? (在这种情况下为Foo
)。执行ICloneable
来返回它自己的一个实例,而不是任何它幻想的随机类型将是很好的。任何将通用接口约束为实现它的类型的方法?
不,基本上。你不能用通用约束来做到这一点。此外,您无法阻止他们多次使用不同的T
(只要这些T
满足任何where
约束条件,在这种情况下都不是)。
没有where
限制允许限制实施类型。
你还挺有几分可以做到这一点的方法参数的限制,但它不是真正令人满意:
public static T SuperClone<T>(this T original) where T : ICloneable<T> {...}
@ AlessandroD'Andria我相信你错了。另见http://blogs.msdn.com/b/ericlippert/archive/2011/02/03/curiouser-and-curiouser.aspx –
需要注意的是,可以使用代码契约来表达这一点。通常这是在运行时检查,但它有可能得到一个编译时警告(见注释后):
它是这样的:
[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();
这些都会CAU SE运行时代码合同失效:
var bad = new BadFoo();
bad.Clone();
var alsoBad = new BadFoo();
alsoBad.Clone();
请注意,您可以得到一个编译时实时预警。
如果你做一个完整的代码契约静态检查的编译,你会看到有关的警告“确保未经证实”为Clone()
为class BadFoo
和class AlsoBad
的实现。
GoodFoo.Clone()
由于Contract.Assume(result.GetType() == this.GetType());
的实施没有任何警告。
然而,代码契约静态检查是(在我看来)仍然是任何东西,但偶尔检查速度太慢,但您的里程可能会有所不同...
当你执行'ICloneable',你必须返回一个' Foo'或派生的。我在这里错过了什么吗? –
@YuvalItzchakov我相信的一点是'Foo'可以同样容易':ICloneable' –
哦,我明白了。谢谢你的澄清@MarcGravell –