2012-10-15 24 views
5

如果有以下方法檢查:類型上可空<int>

static void DoSomethingWithTwoNullables(Nullable<int> a, Nullable<int> b) 
{ 
    Console.WriteLine("Param a is Nullable<int>: " + (a is Nullable<int>)); 
    Console.WriteLine("Param a is int   : " + (a is int)); 
    Console.WriteLine("Param b is Nullable<int>: " + (b is Nullable<int>)); 
    Console.WriteLine("Param b is int   : " + (b is int)); 
} 

當我把這種方法用null作爲一個參數,類型檢查返回此參數錯誤。例如該代碼

DoSomethingWithTwoNullables(5, new Nullable<int>()); 

結果輸出:

Param a is Nullable<int>: True 
Param a is int   : True 
Param b is Nullable<int>: False 
Param b is int   : False 

使用可空,並傳遞null時,有沒有什麼辦法來保存類型的信息?我知道在這個例子中檢查類型是無用的,但它說明了這個問題。在我的項目中,我將參數傳遞給採用params object[]數組的另一種方法,並嘗試識別對象的類型。此方法需要爲Nullable<int>Nullable<long>做不同的事情。

回答

5

直接回答潛在的問題,不,你不能這樣做。空Nullable<int>與空Nullable<long>具有完全相同的裝箱表示,或者確實是'普通'空。沒有辦法知道它是什麼類型的null,因爲它的底層表示只是全零。有關更多詳細信息,請參閱Boxing Nullable Types

+0

由於b首先被裝箱到'int?',從而產生空引用。 – usr

+0

假設你可以嘗試{}抓住{}來測試它,所以有一種方法可以找出答案。我敢打賭,你可以採取進一步的反思,並打磨它。也許初始化一個新的實例,應該給它一個默認值,並執行'typeof(variable.value)'? – NibblyPig

+0

@SLC:你不行。它只是一個沒有類型信息的空引用。 – usr

0

不幸的是,null沒有指向任何特定的內存位置,因此沒有可以與它關聯的元數據來查找類型。因此,您無法獲得有關該變量的任何其他信息。

3

概念上,new Nullable<int>null

如果我們概括,忘記了Nullable<T>

string s = null; 
bool b = s is string; 

我們得到falsefalse預期的值,用於對null值進行類型檢查。

+1

如果他做了'b = 3;'?如果它是一個字符串,那麼你會得到一個錯誤,但如果它是一個int或空的int你不會得到一個錯誤? – NibblyPig

1

您可以嘗試使用反射來實現此目的。 Relevant article here.

+1

你不能使用反射。在空引用上調用'GetType()'會拋出'NullReferenceException'。沒有與空引用關聯的類型。鏈接的文章基於類型而不是對象的引用(在這種情況下可能爲空)。 –

+0

@Martin是正確的。 –

0

除非我誤解了這個問題,否則您可以使用GetType()獲得該類型。例如,

int? myNullableInt = null; 
Console.WriteLine(myNullableInt.GetValueOrDefault().GetType()); 

如果myNullableInt爲空,將返回默認值。檢查返回值的類型,在這種情況下,它將返回System.Int32。您可以對返回的類型執行If..else/Switch檢查以執行相關操作。

int?相同Nullable<int>

+0

或者你可以調用'Nullable.GetUnderlyingType()' – phoog

+0

或者那個。無論哪種方式,似乎都有可能獲得這個問題所需的信息。 – keyboardP

+0

問題是我不知道給定的對象是否爲可空。它也可以是一個字符串或一個純int。我想我可以使用類型檢查來獲取這些信息。但似乎並非如此。 –

0

你不能做到這一點,也不應該希望。由於Nullable<T>是一個結構體,因此此類型的值型變量在編譯時具有所需的所有類型信息。只需使用typeof運算符。

另一方面,您可能有一個Nullable實例,其類型在編譯時不知道。那必須是一個變量,其靜態類型爲object或其他引用類型。不管怎麼樣,因爲一個Nullable<T>價值盒到一個盒裝T價值,有沒有這樣的東西作爲盒裝Nullable<T>該實例的類型您的檢查將只是一個T

這就是爲什麼你得到相同的結果is intis Nullable<int>。沒有辦法區分盒裝int和盒裝int?,因爲沒有盒裝int?

有關詳細信息,請參見Nulls not missing anymore

0

因爲已經指出null沒有類型。要找出是否int? vs long?您需要使用反射來獲取有關存儲類型的信息。下面是一些代碼,你可以爲靈感使用(不知道到底你努力實現代碼時有點怪):

class Pair<T> where T : struct { 

    public Pair(T? a, T? b) { 
    A = a; 
    B = b; 
    } 

    public T? A { get; private set; } 

    public T? B { get; private set; } 

} 

void DoSomething<T>(Pair<T> pair) where T : struct { 
    DoMore(pair); 
} 

void DoMore(params object[] args) { 
    Console.WriteLine("Do more"); 
    var nullableIntPairs = args.Where(IsNullableIntPair); 
    foreach (Pair<int> pair in nullableIntPairs) { 
    Console.WriteLine(pair.A); 
    Console.WriteLine(pair.B); 
    } 
} 

bool IsNullableIntPair(object arg) { 
    var type = arg.GetType(); 
    return type.IsGenericType 
    && type.GetGenericTypeDefinition() == typeof(Pair<>) 
    && type.GetGenericArguments()[0] == typeof(int); 
} 

如果執行下面的代碼

DoSomething(new Pair<int>(5, new int?())); 
DoSomething(new Pair<long>(new long?(), 6L)); 

你會得到下面的輸出:

 
Do more 
5 
null 
Do more 
0

可以使用的typeof:

a == typeof(Nullable<int>) //true 
a == typeof(int) //false