2011-11-06 121 views
1

我有一個IEnumerable<T>參數的方法。
T可以是built-in .NET typesintstring或自定義類這樣的一個:如何從IEnumerable <MyClass>告訴IEnumerable <int>?

class MyClass 
{ 
    public string Foo{ get; set; } 
    public int Bar{ get; set; } 
} 

我怎麼能認識編程如果T是內置類型之一?

我知道我可以做這樣的事情:

switch (typeof(T).Name.ToLower()) 
{ 
    case "int":   
    case "string": 
    case "...": // and so on... 
     Console.WriteLine("It's a built-in type!"); 
     break; 
    default: 
     Console.WriteLine("It's a custom class!"); 
     break; 
} 

...但必須有一個較短/更簡單的方法,對嗎?


編輯:

好的球員,非常感謝你的答案爲止。
但我仍然不確定哪一個是最適合我的情況。

什麼其實我是想做到這一點:
我正在寫一個庫IEnumerable<T>s轉化爲ADODB.Recordsets
在每次轉換開始時,我需要創建一個空的Recordset並向其添加字段。

如果T是一個自定義類,我必須loop through its properties並在記錄集中爲每個屬性T(帶有屬性的名稱和類型)創建一個字段。

但是,如果T是自定義類,則通過屬性循環才能正常工作。
例如,它Tstring,我得到stringCharsLength)的屬性,在這種情況下這對我沒有用處。

這意味着只檢查它是否是原始類型是不夠的 - 我需要識別DateTimeGUID之類的東西,並且可能還有更多。
(我不得不承認,我沒有注意到DateTime不在內置類型列表中)。

所以我想我真正想要的是:
如果T有用戶定義的屬性,我可以循環,或不。

這是否有意義(如果它在所有喜歡int我不關心像string沒有屬性或屬性無論)?

但是,我仍然不確定選擇哪個答案。
driis'和Jon Skeet的答案都意味着我基本上必須列出很多類型(Jon的答案比Driis的答案更多)。
目前,我傾向於選擇Ron Sijm的回答(儘管人們顯然更喜歡其他答案),因爲我想簡單地檢查"System."是做我想做的事情的最短途徑,即使它看起來不好,那優雅的...

+2

可能的重複[有沒有函數來檢查一個對象是否是內置數據類型?](http://stackoverflow.com/questions/1114799/is-there-a-function-to-check-if- an-object-is-a-builtin-data-type) – Damith

+0

如果有人有興趣,我只寫了一個[answer](http://stackoverflow.com/questions/8029023/how-to-tell-an-ienumerableint -from-an-ienumerablemyclass/8056852#8056852)關於我爲什麼選擇Jon的答案以及我的實際解決方案的外觀。 –

回答

5

你確定是一個「內置類型」可能是上下文特定的 - 例如,你已經列出了C#語言內置的類型,但真的特定於C#。它包括decimal(不是CLR基本類型),但不包括DateTime(其他語言可以明確支持)。

所以,我只是用你適當地創建其中HashSet<Type>

private static readonly HashSet<Type> BuiltInTypes = new HashSet<Type> 
{ 
    typeof(object), typeof(string), typeof(byte), typeof(sbyte), 
    // etc 
}; 

// Then: 
if (BuiltInTypes.Contains(typeof(T))) 
{ 
    Console.WriteLine("It's a built-in type!"); 
} 
else 
{ 
    Console.WriteLine("It's a custom class!"); 
} 
+0

好的一點,我沒有意識到內置類型在所有CLR語言中都不相同。我剛剛編輯了這個問題來解釋我真正想要做的事情(將'IEnumerable '轉換爲'ADODB.Recordset')。所以我實際上需要**兩個**不同類型的系統(.net和ADO)......我想如果沒有明確列出類型,就很難做到這一點,正如你所建議的那樣。 –

6

這取決於你定義什麼是「內置類型」。在許多情況下,您可以查看該類型是原始類型還是字符串。 (因爲字符串被認爲是「內置的」,但它不是原始的)。

if (typeof(T).IsPrimitive || typeof(T) == typeof(string)) 
    Console.WriteLine("It's a built-in type"); 

這工作,如果你不滿足於這些原語(from MSDN):

的基本類型是布爾,字節,爲SByte,Int16的,UINT16,的Int32, UInt32的,Int64的,UINT64, IntPtr,UIntPtr,Char,Double和Single。

請記住,類型名稱int只是Int32的C#別名。

編輯

爲了確定可在記錄直接作爲一個字段類型,我可能會看IsPrimitive第一,然後有直接由支持其他的「單值類型」的一個HashSet ADO。包括類型的頭腦風暴變成Guid,Decimal,stringDateTime。我不認爲其他人太多,但我可能是錯的。

當然,直接駐留在System命名空間中的類型將是一種簡單的方法,但在第一次有人向您傳遞一個System.AppDomainSystem.Uri時,您將遇到麻煩。基本上,如果你看看System命名空間中的內容,絕大多數類型不是你應該試圖放在單個字段中的。

+0

你是對的:恐怕原始類型是不夠的。我提供了更多關於我在問題中想要做什麼的細節。 –

+0

我根據您的編輯更新了一些更詳細的答案。 – driis

0

你可以使用(typeof(T).FullName.StartsWith("System."))

+0

但System.DateTime和其他,不是「內置類型」。 – driis

+1

是的,你是對的,它不是「內置類型」之一。但由於他的代碼示例,在我看來,他只是想檢查它是否是他自己創建的內容(如他的MyClass),或者它是「內置的」 –

+0

DateTime由Microsoft提供,作爲。淨。聲音內置於我身上。雖然我會檢查'typeof(T).Assembly',因爲我不認爲.NET禁止你使用System命名空間作爲自己的類。 –

0

我喜歡用Type.GetTypeCode()用於處理數據庫的基本概念,'。你可以有一個簡單的條件,告訴你,如果它是原始的這麼一個數據庫:

bool isDBPrimitive = Type.GetTypeCode(typeof(T)) != Object; 

GetTypeCode()的返回類型爲TypeCode枚舉將返回下面的枚舉值之一,如果該類型相匹配,否則會返回TypeCode.Object枚舉值:

的DBNull
布爾
字符
爲SByte
01字節 的Int16
UINT16
的Int32
UInt32的
的Int64
UINT64


小數
日期時間
字符串

值得注意遺漏GuidDateTimeOffset和可爲空的類型(雖然可以使用typeof(T).GetGenericTypeDefinition() == typeof(Nullable<>)來檢查對象是否爲空,然後使用Nullable.GetUnderlyingType(typeof(T))方法獲得可與GetTypeCode()一起使用的非空類型。

0

我很難決定是否喜歡driis或Jon的答案,但最終我選擇接受Jon的答案。

任何有興趣,我想闡述一下爲什麼我認爲這個答案對我來說是最好的解決辦法了一下:

我一眼就喜歡.IsPrimitive比所有類型填充一個HashSet更好。
但是,一旦提到stringdatetime這樣的特殊情況,很顯然我不會用if (typeof(T).IsPrimitive)這樣的簡短解決方案逃脫。

所以我想詳細瞭解我的實際使用情況下(從轉換到IEnumerable<T>ADODB.Recordset)和我注意到,爲CLR類型的實際轉換到ADO類型,我需要的同時列出了種類型反正。
(要知道,一個Int16需要被轉換成ADODB.DataTypeEnum.adSmallInt,等等)

所以在最後我做類似像喬恩一些建議,但我用一個Dictionary握着我的支持CLR類型相應的ADO類型:

internal static class DataTypes 
{ 
    private static readonly Dictionary<Type, ADODB.DataTypeEnum> Types 
     = new Dictionary<Type, ADODB.DataTypeEnum>() 
     { 
      { typeof(Boolean), ADODB.DataTypeEnum.adBoolean }, 
      { typeof(DateTime), ADODB.DataTypeEnum.adDate }, 
      // and so on... 
     }; 

    public static bool TryGetAdoTypeForClrType(Type clrType, out ADODB.DataTypeEnum adoType) 
    { 
     return Types.TryGetValue(clrType, out adoType); 
    } 
} 

我可以稍後使用它來將我的POCO屬性轉換爲ADO字段的實際工作。

而且我還可以檢查IEnumerable<T>T我開始轉換之前,因爲如果TryGetAdoTypeForClrType(typeof(T), ...)發現的東西,那麼T不能是POCO /自定義類。

這可能不是最完美的解決方案,如果你需要告訴從IEnumerable<MyClass>IEnumerable<int>其他原因比我好,但我認爲它至少爲使用情況下,最好的解決辦法了。

相關問題