簡體   English   中英

通用類型檢查

[英]Generic type checking

有沒有辦法強制/限制傳遞給原語的類型? (布爾、整數、字符串等)

現在,我知道您可以通過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 中完成嗎? 創建一個接口,並在擴展方法中實現該接口(這可能比有點胖的開關更干凈)。 另外,如果您以后需要擴展到任何輕量級自定義類型,它們也可以實現相同的接口,而無需更改基本代碼。

你們有什么感想?

可悲的消息是我在框架 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!

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

這似乎完成了這項工作..

基元似乎在TypeCode枚舉中指定:

也許有一種方法可以找出對象是否包含TypeCode enum ,而無需將其強制轉換為特定對象或調用GetType()typeof()

更新它就在我的眼皮底下。 那里的代碼示例顯示了這一點:

static void WriteObjectInfo(object testObject)
{
    TypeCode    typeCode = Type.GetTypeCode( testObject.GetType() );

    switch( typeCode )
    {
        case TypeCode.Boolean:
            Console.WriteLine("Boolean: {0}", testObject);
            break;

        case TypeCode.Double:
            Console.WriteLine("Double: {0}", testObject);
            break;

        default:
            Console.WriteLine("{0}: {1}", typeCode.ToString(), testObject);
            break;
        }
    }
}

它仍然是一個丑陋的開關。 但這是一個很好的起點!

@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 中。

如果您可以容忍使用工廠方法(而不是您要求的構造函數 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 ,它繼承自MyClass<AnyTypeItDoesntMatter> (具體來說,假設為MyClass<int> 。)因為您可以通過派生類的名稱調用在基類中定義的靜態方法,所以您現在可以使用MyClass.FromString

這為您提供了靜態檢查,但代價是更多的寫入。

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

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

例子:

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

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

但是,我擔心的是,它是否會誤導使用您的課程的潛在開發人員?

干杯-謝謝。

@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

您可以使用typeof(PrimitiveDataType).IsPrimitive屬性來簡化EnforcePrimitiveType方法。 我錯過了什么嗎?

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

在 dotnet 6 中,我在使用struct時遇到了這個錯誤:

類型“字符串”必須是不可為空的值類型才能將其用作參數“T”

所以我改用 IConvertible

var intClass = new PrimitivesOnly<int>();
var doubleClass = new PrimitivesOnly<double>();
var boolClass = new PrimitivesOnly<bool>();
var stringClass = new PrimitivesOnly<string>();
var myAwesomeClass = new PrimitivesOnly<MyAwesomeClass>(); // illegal

// The line below encounter issue when using "string" type
// class PrimitivesOnly<T> where T : struct
class PrimitivesOnly<T> where T : IConvertible
{
    
}

class MyAwesomeClass
{
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM