c# - template - type parameter




通用類型檢查 (6)

@Rob, Enum將通過TypeValid函數,因為它的TypeCodeInteger 。 我已經更新了函數以檢查Enum

Private Function TypeValid() As Boolean
    Dim g As Type = GetType(T)
    Dim code As TypeCode = Type.GetTypeCode(g)

    ' All of the TypeCode Enumeration refer Primitive Types
    ' with the exception of Object and Empty (Nothing).
    ' Note: must also catch Enum as its type is Integer.
    Select Case code
        Case TypeCode.Object
            Return False
        Case Else
            ' Enum's TypeCode is Integer, so check BaseType
            If g.BaseType Is GetType(System.Enum) Then
                Return False
            Else
                Return True
            End If
    End Select
End Function

有沒有辦法強制/限制傳遞給基元的類型? (bool,int,string等)

現在,我知道您可以通過where子句將泛型類型參數限制為類型或接口實現。 然而,這不符合基元(AFAIK)的費用,因為它們並非都有共同點(除了對象之前有人說!:P)。

所以,我目前的想法只是咬緊牙關並做一個大的switch語句並在失敗時拋出ArgumentException

編輯1:

只是為了澄清:

代碼定義應該是這樣的:

public class MyClass<GenericType> ....

並實例化:

MyClass<bool> = new MyClass<bool>(); // Legal
MyClass<string> = new MyClass<string>(); // Legal
MyClass<DataSet> = new MyClass<DataSet>(); // Illegal
MyClass<RobsFunkyHat> = new MyClass<RobsFunkyHat>(); // Illegal (but looks awesome!)

編輯2

@Jon Limjap - 好點,我正在考慮的事情......我確信有一個通用的方法可以用來確定類型是值還是引用類型。

這可以用於立即刪除我不想處理的很多對象(但是你需要擔心使用的結構,比如Size )。有趣的問題不是嗎? :)

這裡是:

where T : struct

取自MSDN

我很好奇..可以使用擴展方法在.NET 3.x中完成嗎? 創建一個接口,並在擴展方法中實現接口(這可能比胖胖的開關更乾淨)。 此外,如果您稍後需要擴展到任何輕量級自定義類型,它們也可以實現相同的接口,而不需要對基本代碼進行任何更改。

你們有什麼感想?

可悲的消息是我在Framework 2中工作!! :d

編輯3

Jon Limjaps Pointer開始,這非常簡單。這麼簡單,我幾乎想哭,但它很棒,因為代碼就像一個魅力!

所以這就是我所做的(你會笑!):

代碼添加到泛型類中

bool TypeValid()
{
    // Get the TypeCode from the Primitive Type
    TypeCode code = Type.GetTypeCode(typeof(PrimitiveDataType));

    // All of the TypeCode Enumeration refer Primitive Types
    // with the exception of Object and Empty (Null).
    // Since I am willing to allow Null Types (at this time)
    // all we need to check for is Object!
    switch (code)
    {
        case TypeCode.Object:
            return false;
        default:
            return true;
    }
}

然後用一個小實用工具方法檢查類型並拋出異常,

private void EnforcePrimitiveType()
{
    if (!TypeValid())
        throw new InvalidOperationException(
            "Unable to Instantiate SimpleMetadata based on the Generic Type of '" + typeof(PrimitiveDataType).Name + 
            "' - this Class is Designed to Work with Primitive Data Types Only.");
}

那麼需要做的就是在類構造函數中調用EnforcePrimitiveType() 。 任務完成! :-)

唯一的缺點是,它只在運行時拋出一個異常(顯然)而不是設計時間。但這沒什麼大不了的,可以用像FxCop這樣的實用程序(我們不在工作中使用)來獲取。

特別感謝Jon Limjap對這一個!


使用自定義FxCop規則來標記MyClass<>不良用法。


如果您可以容忍使用工廠方法(而不是您要求的構造函數MyClass),您可以始終執行以下操作:

class MyClass<T>
{
  private readonly T _value;

  private MyClass(T value) { _value = value; }

  public static MyClass<int> FromInt32(int value) { return new MyClass<int>(value); }
  public static MyClass<string> FromString(string value) { return new MyClass<string>(value); }
  // etc for all the primitive types, or whatever other fixed set of types you are concerned about
}

這裡的一個問題是你需要輸入MyClass<AnyTypeItDoesntMatter>.FromInt32 ,這很煩人。 如果你想維護構造函數的私有性,有一個非常好的方法,但這裡有幾個解決方法:

  • 創建一個抽像類MyClass 。 使MyClass<T>繼承自MyClass 並將其嵌套在MyClass 。 將靜態方法移動到MyClass 。 這將使所有可見性工作,代價是必須訪問MyClass<T>作為MyClass.MyClass<T>
  • 使用給定的MyClass<T> 。 創建一個靜態類MyClass ,它使用MyClass<AnyTypeItDoesntMatter>調用MyClass<T>的靜態方法(每次可能使用適當的類型,只是為了咯咯笑)。
  • (更簡單,但肯定很奇怪)創建一個繼承自MyClass<AnyTypeItDoesntMatter>的抽像類型MyClass 。 (具體來說,假設MyClass<int> 。)因為您可以通過派生類的名稱調用基類中定義的靜態方法,所以現在可以使用MyClass.FromString

這樣可以以更多的寫入為代價進行靜態檢查。

如果您對動態檢查感到滿意,我會在上面的TypeCode解決方案中使用一些變體。


幾乎@Lars已經說過了:

//Force T to be a value (primitive) type.
public class Class1<T> where T: struct

//Force T to be a reference type.
public class Class1<T> where T: class

//Force T to be a parameterless constructor.
public class Class1<T> where T: new()

所有工作都在.NET 2,3和3.5中完成。


遇到類似的挑戰,我想知道你們對IConvertible界面的感受。 它允許請求者需要的內容,您可以使用自己的實現進行擴展。

例:

    public class MyClass<TKey>
    where TKey : IConvertible
{
    // class intentionally abbreviated
}

我認為這是一個解決方案,儘管許多建議也是我選擇的一部分。

但我擔心的是,對於使用你班級的潛在開發人員來說,這會產生誤導嗎?

乾杯 - 謝謝。


public class Class1<GenericType> where GenericType : struct
{
}

這個似乎做了這個工作..







type-safety