Jeszcze raz jedno z tych: „Czy istnieje łatwiejszy wbudowany sposób robienia rzeczy zamiast mojej metody pomocniczej?”
Dlatego łatwo jest uzyskać typ bazowy z typu dopuszczającego wartość null, ale jak uzyskać wersję dopuszczającą wartość null dla typu .NET?
Więc mam
typeof(int)
typeof(DateTime)
System.Type t = something;
i chcę
int?
DateTime?
lub
Nullable<int> (which is the same)
if (t is primitive) then Nullable<T> else just T
Czy istnieje wbudowana metoda?
null
błąd, kiedy przekazuję typ wartości do tej funkcji.type
nie jest null przed uzyskaniem dostępu doIsValueType
właściwości, jak powiedział @AmitG. -1, dopóki to nie zostanie naprawioneMam kilka metod, które napisałem w mojej bibliotece narzędziowej, na których bardzo polegałem. Pierwsza to metoda, która konwertuje dowolny Type na odpowiadający mu formularz Nullable <Type>:
/// <summary> /// [ <c>public static Type GetNullableType(Type TypeToConvert)</c> ] /// <para></para> /// Convert any Type to its Nullable<T> form, if possible /// </summary> /// <param name="TypeToConvert">The Type to convert</param> /// <returns> /// The Nullable<T> converted from the original type, the original type if it was already nullable, or null /// if either <paramref name="TypeToConvert"/> could not be converted or if it was null. /// </returns> /// <remarks> /// To qualify to be converted to a nullable form, <paramref name="TypeToConvert"/> must contain a non-nullable value /// type other than System.Void. Otherwise, this method will return a null. /// </remarks> /// <seealso cref="Nullable<T>"/> public static Type GetNullableType(Type TypeToConvert) { // Abort if no type supplied if (TypeToConvert == null) return null; // If the given type is already nullable, just return it if (IsTypeNullable(TypeToConvert)) return TypeToConvert; // If the type is a ValueType and is not System.Void, convert it to a Nullable<Type> if (TypeToConvert.IsValueType && TypeToConvert != typeof(void)) return typeof(Nullable<>).MakeGenericType(TypeToConvert); // Done - no conversion return null; }
Druga metoda po prostu raportuje, czy dany typ dopuszcza wartość null. Ta metoda jest wywoływana przez pierwszą i jest przydatna osobno:
/// <summary> /// [ <c>public static bool IsTypeNullable(Type TypeToTest)</c> ] /// <para></para> /// Reports whether a given Type is nullable (Nullable< Type >) /// </summary> /// <param name="TypeToTest">The Type to test</param> /// <returns> /// true = The given Type is a Nullable< Type >; false = The type is not nullable, or <paramref name="TypeToTest"/> /// is null. /// </returns> /// <remarks> /// This method tests <paramref name="TypeToTest"/> and reports whether it is nullable (i.e. whether it is either a /// reference type or a form of the generic Nullable< T > type). /// </remarks> /// <seealso cref="GetNullableType"/> public static bool IsTypeNullable(Type TypeToTest) { // Abort if no type supplied if (TypeToTest == null) return false; // If this is not a value type, it is a reference type, so it is automatically nullable // (NOTE: All forms of Nullable<T> are value types) if (!TypeToTest.IsValueType) return true; // Report whether TypeToTest is a form of the Nullable<> type return TypeToTest.IsGenericType && TypeToTest.GetGenericTypeDefinition() == typeof(Nullable<>); }
Powyższa implementacja IsTypeNullable działa jak mistrz za każdym razem, ale jest nieco rozwlekła i powolna w ostatniej linii kodu. Następująca treść kodu jest taka sama jak powyżej dla IsTypeNullable, z tą różnicą, że ostatnia linia kodu jest prostsza i szybsza:
// Abort if no type supplied if (TypeToTest == null) return false; // If this is not a value type, it is a reference type, so it is automatically nullable // (NOTE: All forms of Nullable<T> are value types) if (!TypeToTest.IsValueType) return true; // Report whether an underlying Type exists (if it does, TypeToTest is a nullable Type) return Nullable.GetUnderlyingType(TypeToTest) != null;
Cieszyć się!
znak
PS - Informacje o „nullability”
Powinienem powtórzyć stwierdzenie o nieważności, które zawarłem w osobnym poście, które dotyczy bezpośrednio właściwego zajęcia się tym tematem. Oznacza to, że uważam, że dyskusja tutaj nie powinna skupiać się na tym, jak sprawdzić, czy obiekt jest ogólnym typem Nullable, ale raczej na tym, czy można przypisać wartość null obiektowi tego typu. Innymi słowy, myślę, że powinniśmy określić, czy typ obiektu dopuszcza wartość null, a nie, czy jest dopuszczalny. Różnica dotyczy semantyki, a mianowicie praktycznych powodów określania wartości zerowej, która zwykle jest wszystkim, co się liczy.
W systemie używającym obiektów o typach prawdopodobnie nieznanych do czasu wykonania (usługi sieciowe, zdalne wywołania, bazy danych, źródła danych itp.), Częstym wymaganiem jest określenie, czy obiektowi można przypisać wartość null, czy też obiekt może zawierać null. Wykonywanie takich operacji na typach niepodlegających wartości null prawdopodobnie spowoduje błędy, zwykle wyjątki, które są bardzo kosztowne zarówno pod względem wydajności, jak i wymagań dotyczących kodowania. Aby przyjąć wysoce preferowane podejście do proaktywnego unikania takich problemów, konieczne jest ustalenie, czy obiekt dowolnego typu może zawierać wartość null; tj. czy generalnie dopuszcza się zerową wartość.
W bardzo praktycznym i typowym sensie dopuszczalność wartości null w terminach .NET wcale nie musi oznaczać, że typ obiektu jest formą wartości Nullable. W rzeczywistości w wielu przypadkach obiekty mają typy referencyjne, mogą zawierać wartość null, a zatem wszystkie dopuszczają wartość null; żaden z nich nie ma typu Nullable. Dlatego ze względów praktycznych w większości scenariuszy testowanie powinno być przeprowadzane dla ogólnej koncepcji dopuszczalności wartości zerowej w porównaniu z koncepcją dopuszczalności zerowej zależnej od implementacji. Dlatego nie powinniśmy skupiać się wyłącznie na typie .NET Nullable, ale raczej uwzględnić nasze zrozumienie jego wymagań i zachowania w procesie skupiania się na ogólnej, praktycznej koncepcji zerowalności.
źródło
Odpowiedź Lymana jest świetna i pomogła mi, jednak jest jeszcze jeden błąd, który należy naprawić.
Nullable.GetUnderlyingType(type)
powinno nazywać się tylko wtedy, gdy typ nie jest jużNullable
typem. W przeciwnym razie wydaje się, że błędnie zwraca wartość null, gdy typ pochodzi zSystem.RuntimeType
(na przykład gdy przekazujętypeof(System.Int32)
). Poniższa wersja pozwala uniknąć konieczności wywoływaniaNullable.GetUnderlyingType(type)
, sprawdzając, czyNullable
zamiast tego typ jest .Poniżej znajdziesz plik
ExtensionMethod
wersję tej metody, która natychmiast zwraca typ , chyba że jest toValueType
, że nie jest jużNullable
.Type NullableVersion(this Type sourceType) { if(sourceType == null) { // Throw System.ArgumentNullException or return null, your preference } else if(sourceType == typeof(void)) { // Special Handling - known cases where Exceptions would be thrown return null; // There is no Nullable version of void } return !sourceType.IsValueType || (sourceType.IsGenericType && sourceType.GetGenericTypeDefinition() == typeof(Nullable<>) ) ? sourceType : typeof(Nullable<>).MakeGenericType(sourceType); }
(Przepraszam, ale nie mogłem po prostu opublikować komentarza do odpowiedzi Lymana, ponieważ byłem nowy i nie miałem jeszcze wystarczającej liczby powtórzeń).
źródło
Nie ma nic wbudowanego, o czym wiem, ponieważ
int?
itp. Jest po prostu cukrem syntaktycznymNullable<T>
; i poza tym nie jest traktowany inaczej. Jest to szczególnie mało prawdopodobne, biorąc pod uwagę, że próbujesz uzyskać to z informacji o typie danego typu. Zwykle zawsze wymaga to „zrolowania własnego” kodu jako danego. Będziesz musiał użyć odbicia, aby utworzyć nowyNullable
typ z parametrem typu typu wejściowego.Edycja: Jak sugerują komentarze, w rzeczywistości
Nullable<>
jest traktowany specjalnie i w środowisku wykonawczym do rozruchu, jak wyjaśniono w tym artykule .źródło
int?
za pośrednictwem+
operatora, wiemy, żeNullable
jest to traktowane w specjalny sposób, ponieważ tego rodzaju ogólne przeciążenie operatora nie zadziałałoby inaczej.