2014-06-23 42 views
1
public interface ICloneable<T> 
{ 
    T Clone(); 
} 

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

有什麼辦法可以將T約束爲實現接口的類型嗎? (在這種情況下爲Foo)。執行ICloneable來返回它自己的一個實例,而不是任何它幻想的隨機類型將是很好的。任何將通用接口約束爲實現它的類型的方法?

+0

當你執行'ICloneable ',你必須返回一個' Foo'或派生的。我在這裏錯過了什麼嗎? –

+0

@YuvalItzchakov我相信的一點是'Foo'可以同樣容易':ICloneable ' –

+0

哦,我明白了。謝謝你的澄清@MarcGravell –

回答

5

不,基本上。你不能用通用約束來做到這一點。此外,您無法阻止他們多次使用不同的T(只要這些T滿足任何where約束條件,在這種情況下都不是)。

沒有where限制允許限制實施類型。

你還挺有幾分可以做到這一點的方法參數的限制,但它不是真正令人滿意:

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

@ AlessandroD'Andria我相信你錯了。另見http://blogs.msdn.com/b/ericlippert/archive/2011/02/03/curiouser-and-curiouser.aspx –

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

這些都會CAU SE運行時代碼合同失效:

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

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

請注意,您可以得到一個編譯時實時預警。

如果你做一個完整的代碼契約靜態檢查的編譯,你會看到有關的警告「確保未經證實」爲Clone()class BadFooclass AlsoBad的實現。

GoodFoo.Clone()由於Contract.Assume(result.GetType() == this.GetType());的實施沒有任何警告。

然而,代碼契約靜態檢查是(在我看來)仍然是任何東西,但偶爾檢查速度太慢,但您的里程可能會有所不同...

相關問題