почему typeof int?
a Int32
int? x = 1;
Console.WriteLine(x.GetType().Name);
Если все в порядке, то какое использование Nullable.GetUnderlyingType
?
почему typeof int?
a Int32
int? x = 1;
Console.WriteLine(x.GetType().Name);
Если все в порядке, то какое использование Nullable.GetUnderlyingType
?
Вызов GetType()
блокирует вашу переменную. CLR имеет специальное правило, что Nullable<T>
помещается в поле T
. Поэтому x.GetType
вернет Int32
вместо Nullable<Int32>
.
int? x = 1;
x.GetType() //Int32
typeof(int?) //Nullable<Int32>
Так как a Nullable
, содержащий null
, помещается в квадрат null
, следующее исключает:
int? x = null;
x.GetType() //throws NullReferenceException
Процитировать MSDN по боксу Nullable Types:
Объекты, основанные на типах с нулевым значением, помещаются только в поле, если объект не равен нулю. Если
HasValue
-false
, ссылка на объект присваиваетсяnull
вместо боксаЕсли объект не является нулевым - если
HasValue
-true
- тогда происходит бокс, но вставляется только базовый тип, на который основан объект с нулевым значением. Бокс не равный null null value type вводит тип значения сам, а неSystem.Nullable<T>
, который обертывает тип значения.
Этот пример немного запутан, потому что:
int? x = 1;
создает Nullable<int>
, как вы ожидаете; Однако:
Type tupe = x.GetType();
- это вызов не виртуального метода на object
, который не является (и не может быть) переопределен - поэтому это операция бокса; и Nullable<T>
имеет специальные правила бокса:
null
то есть.
int? x = 1;
int y = 1;
в поле точно.
Следовательно, вы проходите typeof(int)
до GetUnderlyingType
.
Более наглядным примером того, когда это помогает, является использование рефлексии:
class Foo {
public int? Bar {get;set;}
}
...
Type type = typeof(Foo); // usually indirectly
foreach(var prop in type.GetProperties()) {
Type propType = prop.PropertyType,
nullType = Nullable.GetUnderlyingType(propType);
if(nullType != null) {
// special code for handling Nullable<T> properties;
// note nullType now holds the T
} else {
// code for handling other properties
}
}
Его для, когда вы не знаете его Int32
.
public Type GetNullableUnderlyingType<T>(Nullable<T> obj)
where T : struct
{
return Nullable.GetUnderlyingType(typeof(Nullable<T>));
}
Здесь вы можете передать любой объект Nullable
и получить его, чтобы вернуть его базовый тип.
Когда вы пишете int?
, как будто вы написали Nullable<int>
. Я думаю, что тип, который вы ищете.
В основном это для решения общего метода:: например.
public static void SomeMethod<T>(T argument)
{
if(Nullable.GetUnderlyingType(typeof(T) != null)
{
/* special case for nullable code go here */
}
else
{
/* Do something else T isn't nullable */
}
}
Важно знать это, так как некоторые вещи, которые очень дешевы, могут быть невероятно дорогими в nullable. Например, if(argument == null)
обычно супер дешево, но когда это делается в общем методе на Nullable<T>
, принудительно вводится argument
для получения нулевой ссылки. Лучше всего использовать EqualityComparer<T>.Default
, который замедлит все остальное, но делает его недействительным.