2016-08-03 58 views
4

我有一個通用的接口(MyInterface<T>),這是由類ChildA在下面的例子中實現:強制通用接口童車型

public interface MyInterface<T> 
{ 
    MyObj<T> GetObj(); // Irrelevant 
} 

class ChildA : MyInterface<ChildA> 
{ 
    // Irrelevant: 
    MyObj<ChildA> GetObj() { 
     return new MyObj<ChildA>(); 
    } 
} 

這工作,但我需要確保<T>總是有類型的實現類,所以在這種情況下,T應始終爲ChildA類型,因爲它是由ChildA實現的。

另一個正確實現可能是這樣,例如:

class ChildB : MyInterface<ChildB> { ... } 

但目前,這不正確實現也是可行的,但它不應該是:

class ChildA : MyInterface<ChildB> { ... } 

有沒有辦法強制執行?

+2

我不確定你要在這裏做什麼。有可能強制自己的類型,但幾乎沒有收益。它背後的動機是什麼? –

+1

你爲什麼要這樣? –

+0

@MioBambino我正在使用它來實現數據傳輸對象。這一切都已經在工作,但正如我所提到的,仍然有可能將其設置爲另一種類型。這就是爲什麼我需要強制執行那些不可能發生的事情。 –

回答

7

您無法強制將泛型類型參數限制爲實現類型。

可用type constraints如下:

  • where T : struct
  • where T : class
  • where T : new()
  • where T : <base class name>
  • where T : <interface name>
  • where T : U

在C#中沒有什麼像where T : self。事實上,它甚至沒有意義,因爲這樣的事情不能被有效地執行。此外,它根本不適合於協變/逆變的概念,並且一般而言會很奇怪地繼承。

你可以做的最接近的事是這樣的:

public interface IMyInterface<T> where T : IMyInterface<T> 
{ 
    MyObj<T> GetObj(); 
} 

爲什麼就沒有意義

比方說,你可以這樣做:

public interface IMyInterface<T> where T : self // this syntax does not exist in C# 
{ 
    MyObj<T> GetObj(); 
} 

現在所有執行的類型,將必須使用自己作爲類型參數。但你仍然可以這樣做:

public class ChildC<T> : IMyInterface<T> where T : self 
{ 
    /* ... */ 
} 

這將繞過你的限制。

+0

最後一個聲明是不是也需要'where T:self' in爲了編譯? – Groo

+0

@Groo可能是:)取決於語言作者希望它的工作原理 –

+0

現在你需要在泛型類中添加限制,所以假設應用了「self」約束同樣的方式,它很有可能在課堂上正常工作,如果我是對的,也可能要求讓課程'密封',因爲你無法從「合法」中得出結論 – Groo

1

你不能這樣做,但你可以創建自己的控件,比較接口的泛型類型和類的類型。見例如:

class ChildA : MyInterface<ChildB> 
{ 
    public ChildA() 
    { 
     this.ValidateGenericType(); 
    } 

    public MyObj<ChildB> GetObj() 
    { 
     return new MyObj<ChildB>(); 
    } 

    protected void ValidateGenericType() 
    { 
     //throws an Exception because ChildB is different of ChilA 
     if (this.GetType().Name != this.GetType().GetInterfaces()[0].GetGenericArguments()[0].Name) 
     { 
      throw new Exception("The generic type must be of type ChildA."); 
     } 
    } 
} 
1

看來,你應該使用擴展方法,而不是強制執行的一些接口,用於此目的

public interface ISomeInterface {} 

public class Child: ISomeInterface {} 

public class OtherChild : ISomeInterface { } 

public static class MyInterfaceExtensions 
{ 
    public static MyObj<T> GetMyObj<T>(this T child) where T : ISomeInterface 
    { 
     return new MyObj<T>(); 
    } 
} 

public static class Test 
{ 
    public static void RunTest() 
    { 
     var child = new Child(); 
     var otherChild = new OtherChild(); 

     MyObj<Child> myObj = child.GetMyObj(); 
     MyObj<OtherChild> myOtherObj = otherChild.GetMyObj(); 
    } 
} 
2

有沒有辦法強制執行呢?

那麼,不是一般的約束。你可以做到這一點與反思,雖然我會投反對票:

public abstract class BaseChild<T> : MyInterface<T> 
{ 
    protected BaseChild() 
    { 
     if (typeof(T) != this.GetType()) 
     { 
      throw new InvalidOperationException(string.Format(
          "Type {0} is not supported as valid type parameter for type {1}", 
          typeof(T).Name, this.GetType().Name)); 
     } 
    } 
} 

例子:

class ChildA : BaseChild<int> { } 

// Bang! throws 
var instance = new ChildA(); 

class ChildB : BaseChild<ChildB> { } 

// Ok here 
var instance = new ChildB();