Як перевірити, чи об’єкт є нульовим?


202

Як я можу перевірити, чи заданий об'єкт є змінним іншими словами, як реалізувати наступний метод ...

bool IsNullableValueType(object o)
{
    ...
}

EDIT: Я шукаю нульові типи значень. Я не мав на увазі типів реф.

//Note: This is just a sample. The code has been simplified 
//to fit in a post.

public class BoolContainer
{
    bool? myBool = true;
}

var bc = new BoolContainer();

const BindingFlags bindingFlags = BindingFlags.Public
                        | BindingFlags.NonPublic
                        | BindingFlags.Instance
                        ;


object obj;
object o = (object)bc;

foreach (var fieldInfo in o.GetType().GetFields(bindingFlags))
{
    obj = (object)fieldInfo.GetValue(o);
}

Тепер obj посилається на об'єкт типу bool( System.Boolean) зі значенням, рівним true. Те, що я дуже хотів, було предметом типуNullable<bool>

Тож тепер, як обхід, я вирішив перевірити, чи не є нульовим, і створити об'ємну обгортку навколо obj.


Чи повинен код включати рядки як нульові? Вони не є загальним типом ValueType, який здається зведеним нанівець. Або вони не є ValueType?
TamusJRoyce

Рядок не є ValueType. Це еталонний тип.
Suncat2000

Це справді гарне запитання! "Type.IsNullableType ()" є таким чином обманливим, оскільки він фактично перевіряє лише тип "Nullable <T>", який не повертав очікуваних результатів, якщо ви насправді хотіли перевірити наявність будь-яких типів, які можуть прийняти нуль значення (наприклад, я намагався використовувати з a.IsNullableType (), де 'a' був 'typeof (string)', визначеним під час виконання)
ErrCode

Відповідь є у fieldInfo.FieldType: перевірте, чи FieldType є загальним, а загальний тип має значення Nullable <>. (Приклад: if (FieldType.IsGenericType && FieldType.GetGenericTypeDefinition () == typeof (Nullable <>))). Не намагайтеся отримати obj.GetType (), це буде мати змінну UndelyingSystemType Nullable <T> (у вашому випадку булевого типу замість Nullable <Boolean>), це проблема боксу.
SoLaR

Відповіді:


271

Існує два типи мінливих - Nullable<T>та еталонний.

Джон поправив мене, що важко набрати тип, якщо бокс, але можна з дженериками: - так як далі. Це фактично тестовий тип T, але, використовуючи objпараметр виключно для загального виводу типу (щоб спростити виклик) - він би працював майже однаково без objпарам.

static bool IsNullable<T>(T obj)
{
    if (obj == null) return true; // obvious
    Type type = typeof(T);
    if (!type.IsValueType) return true; // ref-type
    if (Nullable.GetUnderlyingType(type) != null) return true; // Nullable<T>
    return false; // value-type
}

Але це не спрацює так добре, якщо ви вже встановили коробку значення в змінну об'єкта.

Документація Майкрософт: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/nullable-types/how-to-identify-a-nullable-type


7
Останній рядок дійсний лише в тому випадку, якщо вам якимось чином вдасться отримати коробку Nullable <T> замість боксу прямо до T. Це можна, але складно досягти з того, що я пам’ятаю.
Джон Скіт

Цей код був для мене корисним не тому, що я отримав ящик Nullable <T>, а тому, що я писав загальний базовий клас конвертора WPF, а деякі властивості є зведеними, тому я використовував Nullable.GetUnderlyingType для виявлення цього випадку та Activator.CreateInstance для створення коробчастий нульовий, (Convert.ChangeType не обробляє нуль btw).
Qwertie

1
@Abel, якщо ви маєте на увазі його редагування, щоб уточнити, що він не враховував типи посилань, я думаю, моя відповідь до цього редагувала; читач може приймати власне рішення там, виходячи з власних потреб, я підозрюю (підтвердив: його коментар повторно вводиться, як додано о 14:42; моя відповідь була все <= 14:34)
Марк Гравелл

1
Чи буде (obj == null) викинути виняток, коли obj = 1?
Ци Фан

3
@JustinMorgan Якщо Tзагальний параметр обмежений T : struct, Tце не дозволяється Nullable<>, тому вам не потрібно перевіряти в цьому випадку! Я знаю, що тип Nullable<>- це структура, але в C # обмеження where T : structспеціально виключають нульові типи значень. Спеціалізація говорить: "Зауважте, що хоча класифікований як тип значення, тип нульового значення (§4.1.10) не відповідає обмеженню типу значення".
Jeppe Stig Nielsen

46

Існує дуже просте рішення з використанням перевантажень методу

http://deanchalk.com/is-it-nullable/

витяг:

public static class ValueTypeHelper
{
    public static bool IsNullable<T>(T t) { return false; }
    public static bool IsNullable<T>(T? t) where T : struct { return true; }
}

тоді

static void Main(string[] args)
{
    int a = 123;
    int? b = null;
    object c = new object();
    object d = null;
    int? e = 456;
    var f = (int?)789;
    bool result1 = ValueTypeHelper.IsNullable(a); // false
    bool result2 = ValueTypeHelper.IsNullable(b); // true
    bool result3 = ValueTypeHelper.IsNullable(c); // false
    bool result4 = ValueTypeHelper.IsNullable(d); // false
    bool result5 = ValueTypeHelper.IsNullable(e); // true
    bool result6 = ValueTypeHelper.IsNullable(f); // true

7
плюс один для вас, сер, для додавання тестових випадків. Я використовував ці тестові випадки для перевірки всіх інших відповідей. Більше людей повинні пройти цей додатковий шматочок.
Марті Ніл

4
Оскільки це варте, це не працює у VB.NET. Це призводить до помилки компілятора " Не вдалося вирішити перевантаження, оскільки жодна доступна" IsNullable "не є найбільш специфічною для цих аргументів " у всіх ситуаціях, де Trueвони будуть повернуті.
ckittel

1
Мені дуже подобається таке рішення - і шкода, що VB не може впоратися з цим. Я спробував попрацювати з ValueType, але зіткнувся з проблемою, коли компілятор VB не відповідав, яку перевантаження використовувати на основі того, чи називався він як спільний метод або розширення, я навіть поставив питання з цього приводу, як здається дивним: stackoverflow.com/ питання / 12319591 /…
Джеймс Закрити

22
Ви перевіряєте тип часу компіляції , але це вже очевидно (з intellisense), якщо тип часу компіляції є нульовим ( System.Nullable<>). Якщо ви скажете object g = e;і тоді ValueTypeHelper.IsNullable(g), що ви очікуєте отримати?
Jeppe Stig Nielsen

18
Я щойно перевірив; це не працює , як сказав Джеппе. Якщо змінні передаються об'єкти, вони завжди повертатимуться хибними. Таким чином, ви не можете визначити тип невідомого об'єкта під час виконання таким чином. Єдиний час, коли це працює, якщо тип фіксується під час компіляції, і в такому випадку вам взагалі не потрібно перевіряти час виконання.
HugoRune

30

Питання "Як перевірити, чи є тип нульовим?" насправді "Як перевірити, чи є тип Nullable<>?", який можна узагальнити до "Як перевірити, чи є тип побудованим типом якогось загального типу?", щоб він не лише відповідав на питання "Чи Nullable<int>є Nullable<>?", але і «Є чи ?».List<int>List<>

Більшість запропонованих рішень використовують Nullable.GetUnderlyingType()метод, який, очевидно, працює лише у випадку Nullable<>. Я не бачив загального рефлексивного рішення, яке буде працювати з будь-яким родовим типом, тому я вирішив додати його сюди для нащадків, хоча на це питання вже давно відповіли.

Для того, щоб перевірити , є чи тип тієї чи іншій формі з Nullable<>допомогою відображення, ви повинні спочатку перетворити сконструйований універсальний тип, наприклад Nullable<int>, у визначенні універсального типу, Nullable<>. Це можна зробити за допомогою GetGenericTypeDefinition()методу Typeкласу. Потім можна порівняти отриманий тип з Nullable<>:

Type typeToTest = typeof(Nullable<int>);
bool isNullable = typeToTest.GetGenericTypeDefinition() == typeof(Nullable<>);
// isNullable == true

Те саме можна застосувати до будь-якого загального типу:

Type typeToTest = typeof(List<int>);
bool isList = typeToTest.GetGenericTypeDefinition() == typeof(List<>);
// isList == true

Кілька типів можуть здаватися однаковими, але різна кількість аргументів типу означає, що це зовсім інший тип.

Type typeToTest = typeof(Action<DateTime, float>);
bool isAction1 = typeToTest.GetGenericTypeDefinition() == typeof(Action<>);
bool isAction2 = typeToTest.GetGenericTypeDefinition() == typeof(Action<,>);
bool isAction3 = typeToTest.GetGenericTypeDefinition() == typeof(Action<,,>);
// isAction1 == false
// isAction2 == true
// isAction3 == false

Оскільки Typeоб'єкт інстанціюється один раз на тип, ви можете перевірити рівність еталонів між ними. Тож якщо ви хочете перевірити, чи два об'єкти мають одне загальне визначення типу, ви можете написати:

var listOfInts = new List<int>();
var listOfStrings = new List<string>();

bool areSameGenericType =
    listOfInts.GetType().GetGenericTypeDefinition() ==
    listOfStrings.GetType().GetGenericTypeDefinition();
// areSameGenericType == true

Якщо ви хочете перевірити, чи об’єкт є нульовим, а не a Type, тоді ви можете використовувати описану вище техніку разом з рішенням Марка Гравелла, щоб створити досить простий метод:

static bool IsNullable<T>(T obj)
{
    if (!typeof(T).IsGenericType)
        return false;

    return typeof(T).GetGenericTypeDefinition() == typeof(Nullable<>);
}

@ AllonGuralnek У моїй відповіді є спрощена версія. Я хотів зробити це редагуванням, і оскільки моя репутація не є вашим рівнем, це було б редагування без мого імені на вашу відповідь, навіть так, здається, що огляд завжди стріляє мені в ногу, що він звертається до автора, навіть якщо це було ні. Дивний світ, деякі люди не отримують визначень :).
ipavlu

@ipavlu: Ваша версія не спрощена, вона насправді складніша. Я думаю, ви маєте на увазі, що це оптимізовано, оскільки ви кешуєте результат. Це ускладнює розуміння.
Аллон Гуралнек

@ AllonGuralnek статичний загальний клас та статичні одноразові ініціалізовані поля, що є складним? Шановний Боже, я вчинив жахливий злочин :).
ipavlu

@ipavku: Так, оскільки це не має нічого спільного з питанням "Як перевірити, чи є об'єкт нульовим?". Я намагаюся тримати це просто і по суті, і уникаю зайвих і непов'язаних понять.
Аллон Гуралнек

1
@nawfal: Якщо я вас правильно зрозумів, ви шукаєте мою реалізацію в умовах існування того, Nullable.GetUnderlyingType()що вже передбачено рамкою. Чому б просто не використовувати метод в рамках? Ну, слід. Він чіткіший, стисліший і краще перевірений. Але в своєму дописі я намагаюся навчити використовувати рефлексію для отримання потрібної інформації, щоб хтось міг застосувати її до будь-якого типу (замінивши typeof(Nullable<>)будь-який інший тип). Якщо ви подивитесь на джерела GetUnderlyingType()(оригінальні чи декомпільовані), то побачите, що це дуже схоже на мій код.
Аллон Гуралнек

30

Це для мене працює і здається простим:

static bool IsNullable<T>(T obj)
{
    return default(T) == null;
}

Для типів значень:

static bool IsNullableValueType<T>(T obj)
{
    return default(T) == null && typeof(T).BaseType != null && "ValueType".Equals(typeof(T).BaseType.Name);
}

7
Чого варто, це також тест, який використовує Microsoft
canton7

1
Приємно ... Це не найкраща відповідь, тому що вона з’явилася пізніше? Я вважаю верхню відповідь такою заплутаною.
Вінсент Бускарелло

1
Це має бути головна відповідь. Після декількох днів спроб різних методів я випадково подумав про це рішення, спробував це, і, здається, він ідеально працює (порівняно з найвищою оцінкою)
user3163495

2
Це відмінне рішення, щоб дізнатися, чи можна встановити будь-який примірник на NULL, але він поверне істинне для всього, що може бути встановлено на нуль, включаючи звичайні об'єкти. Важливо усвідомити, що оригінальне питання спеціально хотіло виявити Nullable ValueTypes.
JamesHoux

20

Ну, ви можете використовувати:

return !(o is ValueType);

... але сам об'єкт не є нульовим чи іншим чином - тип є. Як ви планували використовувати це?


2
Це трохи відкинуло мене. наприклад, int? i = 5; typeof (i) повертає System.Int32 замість Nullable <Int32> - typeof (int?) повертає Nullable <Int32> .. Де я можу отримати ясність з цієї теми?
Gishu

2
typeof (i) дасть помилку компілятора - ви не можете використовувати typeof зі змінною. Що ти насправді робив?
Джон Скіт

15
i.GetType () вперше введено в поле Object, і немає такого поняття, як коробчастий зведений тип - Nullable <int> потрапляє в поле з нульовою посиланням або boxed int.
Джон Скіт

Це краще, ніж Nullable.GetUnderlyingType (type)! = Null?
Кікенет

@Kiquenet: Ми не маємо типу тут - тільки значення.
Джон Скіт

11

Найпростіший спосіб я зрозуміти:

public bool IsNullable(object obj)
{
    Type t = obj.GetType();
    return t.IsGenericType 
        && t.GetGenericTypeDefinition() == typeof(Nullable<>);
}

+1. Відмінне рішення для ящиків, що не входять в коробку. Я цього ще не перевіряв. Тож якщо хтось ще може перевірити, це буде вдячно.
TamusJRoyce

Я це вже перевірив. Мені довелося створити такий Nullableтип, але з різною семантикою. У моїй ситуації я повинен підтримувати nullяк дійсне значення, а також підтримувати взагалі ніяке значення. Так створений Optionalтип. Оскільки це було необхідно для підтримки nullзначень, я також повинен був реалізувати код для обробки Nullableзначень як частина моєї реалізації. Саме звідси і взявся цей код.
CARLOS LOTH

9
Я думаю, що це рішення неправильне. Передача типу Nullable в якості аргументу методу, який очікує параметр об'єкта type, повинен спричинити появу боксу. Nullable - тип значення, а результат перетворення боксу - еталонний тип. Немає ящиків з коробкою. Я вважаю, що цей метод завжди повертається помилковим?
Мішакс

1
Будь-який тест про це, як інша відповідь?
Кікенет

5
Це не працює через значення боксу. Це завжди поверне ЛЮЖЕ.
N Rocking

10

Тут є дві проблеми: 1) тестування, щоб перевірити, чи є тип нерегульованим; і 2) тестування на предмет того, чи представляє об'єкт нульовий тип.

Для випуску 1 (тестування типу) ось рішення, яке я використовував у своїх власних системах: TypeIsNullable-check рішення

Для випуску 2 (тестування об'єкта) рішення Діна Крейда вище працює для типів значень, але він не працює для референтних типів, оскільки при використанні перевантаження <T> завжди повертається помилковим. Оскільки типи посилань по суті є нульовими, тестування референсного типу завжди повинно повернути істину. Будь ласка, дивіться примітку [Про "зведеність"] нижче для пояснення цих семантик. Отже, ось моя модифікація підходу Діна:

    public static bool IsObjectNullable<T>(T obj)
    {
        // If the parameter-Type is a reference type, or if the parameter is null, then the object is always nullable
        if (!typeof(T).IsValueType || obj == null)
            return true;

        // Since the object passed is a ValueType, and it is not null, it cannot be a nullable object
        return false; 
    }

    public static bool IsObjectNullable<T>(T? obj) where T : struct
    {
        // Always return true, since the object-type passed is guaranteed by the compiler to always be nullable
        return true;
    }

І ось моя модифікація клієнтського тестового коду для вищезазначеного рішення:

    int a = 123;
    int? b = null;
    object c = new object();
    object d = null;
    int? e = 456;
    var f = (int?)789;
    string g = "something";

    bool isnullable = IsObjectNullable(a); // false 
    isnullable = IsObjectNullable(b); // true 
    isnullable = IsObjectNullable(c); // true 
    isnullable = IsObjectNullable(d); // true 
    isnullable = IsObjectNullable(e); // true 
    isnullable = IsObjectNullable(f); // true 
    isnullable = IsObjectNullable(g); // true

Причина, що я змінив підхід Діна в IsObjectNullable <T> (T t), полягає в тому, що його оригінальний підхід завжди повертав помилковим для еталонного типу. Оскільки такий метод, як IsObjectNullable, повинен вміти обробляти значення опорного типу і оскільки всі типи посилань притаманні нульовому значенню, то якщо передається або тип посилання, або нуль, метод завжди повинен повертати true.

Вищевказані два способи можна було б замінити наступним єдиним методом та досягти однакового результату:

    public static bool IsObjectNullable<T>(T obj)
    {
        Type argType = typeof(T);
        if (!argType.IsValueType || obj == null)
            return true;
        return argType.IsGenericType && argType.GetGenericTypeDefinition() == typeof(Nullable<>);
    }

Однак проблема цього останнього одно методичного підходу полягає в тому, що продуктивність страждає при використанні параметра Nullable <T>. На виконання останнього рядка цього єдиного методу потрібно набагато більше часу, ніж це дозволяє дозволити компілятору вибрати другий метод перевантаження, показаний раніше, коли в виклику IsObjectNullable використовується параметр типу Nullable <T>. Тому оптимальним рішенням є використання дво методичного підходу, проілюстрованого тут.

CAVEAT: Цей метод працює надійно, лише якщо його викликають з використанням оригінальної посилання на об'єкт або точної копії, як показано в прикладах. Однак якщо об’єкт, що зводить нанівець, розміщується в іншому типі (наприклад, об'єкт тощо) замість того, щоб залишатись у початковій формі Nullable <>, цей метод не працюватиме надійно. Якщо код, що викликає цей метод, не використовує оригінальну, немеханічну посилання на об'єкт або точну копію, він не може достовірно визначити зведеність об'єкта за допомогою цього методу.

У більшості сценаріїв кодування для визначення нульовості потрібно замість того, щоб перевірити тип оригінального об'єкта, а не його посилання (наприклад, код повинен мати доступ до оригінального типу об'єкта для визначення нульовості). У цих більш поширених випадках IsTypeNullable (див. Посилання) є надійним методом визначення нульовості.

PS - Про "зведеність"

Я повинен повторити заяву про мінливість, яку я зробив в окремому дописі, що стосується безпосередньо належного вирішення цієї теми. Тобто, я вважаю, що в центрі обговорення тут не повинно бути те, як перевірити, чи є об'єкт загальним типу Nullable, а скоріше, чи можна призначити значення null об’єкту такого типу. Іншими словами, я думаю, що ми повинні визначати, чи є тип об’єкта нульовим, а не чи є це Nullable. Різниця полягає в семантиці, а саме в практичних причинах визначення нульовості, що, як правило, має значення всього.

У системі, що використовує об'єкти з типами, можливо, невідомими до часу виконання (веб-сервіси, віддалені виклики, бази даних, канали тощо), загальною вимогою є визначення того, чи може бути призначений нуль об'єкту, чи може об'єкт містити нуль. Виконання таких операцій на ненульових типах, ймовірно, призведе до помилок, як правило, винятків, які є дуже дорогими як з точки зору продуктивності, так і з вимогами кодування. Щоб скористатися найбільш вподобаним підходом до попереднього уникнення подібних проблем, необхідно визначити, чи здатний об'єкт довільного типу містити нуль; тобто, чи це взагалі "зведений нанівець".

У дуже практичному та типовому сенсі, зведення в термін .NET зовсім не обов'язково означає, що Тип об'єкта є формою Nullable. У багатьох випадках фактично об'єкти мають еталонні типи, можуть містити нульове значення і, таким чином, всі є нульовими; жоден з них не має типу Nullable. Отже, для практичних цілей у більшості сценаріїв слід проводити тестування на загальну концепцію зведеності, порівняно з концепцією Nullable, залежною від реалізації. Таким чином, ми не повинні відмовлятися, зосереджуючись лише на типі .NET Nullable, а краще включати своє розуміння його вимог та поведінки в процесі зосередження на загальній практичній концепції зведення нанівець.


8

Найпростіше рішення, яке я придумав, - це реалізувати рішення Microsoft ( Як: Визначити тип Nullable (Посібник з програмування C #) ) як метод розширення:

public static bool IsNullable(this Type type)
{
    return Nullable.GetUnderlyingType(type) != null;
}

Потім це можна назвати так:

bool isNullable = typeof(int).IsNullable();

Це також здається логічним способом доступу, IsNullable()оскільки він відповідає всім іншим IsXxxx()методам Typeкласу.


1
Ви не хотіли використовувати "==" замість "! ="?
vkelman

Добре місце @vkelman Замість того, щоб вносити ці зміни, я оновив відповідь, щоб використовувати поточну пропозицію від Microsoft, оскільки це змінилося з часу написання цього.
sclarke81

6

Будьте обережні, боксуючи тип "нульовий" (наприклад, Nullable<int>int?):

int? nullValue = null;
object boxedNullValue = (object)nullValue;
Debug.Assert(boxedNullValue == null);

int? value = 10;
object boxedValue = (object)value;
Debug.Assert( boxedValue.GetType() == typeof(int))

Він стає справжнім еталонним типом, тож ви втрачаєте той факт, що він був незмінним.


3

Можливо, трохи поза темою, але все ж якась цікава інформація. Я знаходжу багато людей, які використовують Nullable.GetUnderlyingType() != nullдля ідентичності, якщо тип є незмінним. Це очевидно працює, але Microsoft радить наступне type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)(див. Http://msdn.microsoft.com/en-us/library/ms366789.aspx ).

Я дивився на це з точки зору продуктивності. Висновок тесту (мільйон спроб) нижче полягає в тому, що коли тип є нульовим, опція Microsoft забезпечує найкращі показники.

Nullable.GetUnderlyingType (): 1335 мс (у 3 рази повільніше)

GetGenericTypeDefinition () == typeof (Nullable <>): 500ms

Я знаю, що ми говоримо про невелику кількість часу, але всі люблять підкручувати мілісекунди :-)! Тож якщо ти начальник хоче, щоб ти зменшив кілька мілісекунд, то це твій рятівник ...

/// <summary>Method for testing the performance of several options to determine if a type is     nullable</summary>
[TestMethod]
public void IdentityNullablePerformanceTest()
{
    int attempts = 1000000;

    Type nullableType = typeof(Nullable<int>);

    Stopwatch stopwatch = new Stopwatch();
    stopwatch.Start();
    for (int attemptIndex = 0; attemptIndex < attempts; attemptIndex++)
    {
        Assert.IsTrue(Nullable.GetUnderlyingType(nullableType) != null, "Expected to be a nullable"); 
    }

    Console.WriteLine("Nullable.GetUnderlyingType(): {0} ms", stopwatch.ElapsedMilliseconds);

    stopwatch.Restart();

    for (int attemptIndex = 0; attemptIndex < attempts; attemptIndex++)
   {
       Assert.IsTrue(nullableType.IsGenericType && nullableType.GetGenericTypeDefinition() == typeof(Nullable<>), "Expected to be a nullable");
   }

   Console.WriteLine("GetGenericTypeDefinition() == typeof(Nullable<>): {0} ms", stopwatch.ElapsedMilliseconds);
   stopwatch.Stop();
}

1
Привіт, мабуть, є одна проблема з вимірюванням часу, Assert може вплинути на результати. Ви протестували без Assert? Також Console.WriteLine повинен знаходитись поза зоною вимірювання. +1 за спробу кількісної оцінки ефективності :).
ipavlu

@ipavlu Console.WriteLineдійсно знаходиться за межами дозованої області;)
nawfal

Рулон, як згадував ipavlu, Assertповинен знаходитися поза петлею. По-друге, ви також повинні перевірити його на ненульові значення, а також перевірити помилкові випадки. Я зробив аналогічний тест (2 нулі та 4 ненульових), і я отримую ~ 2 секунди протягом GetUnderlyingTypeі ~ 1 секунду GetGenericTypeDefinition, тобто GetGenericTypeDefinitionвдвічі швидший (не тричі).
nawfal

Зробив ще один раунд з 2 нульовими і 2 ненульовими - цього разу GetUnderlyingTypeбув у 2,5 рази повільніше. Тільки без нульових значень - цього разу обидва - шия та шия.
nawfal

Але що ще важливіше, GetUnderlyingTypeце корисно, коли вам доведеться перевірити наявність мінливості та отримати базовий тип, якщо він є нульовим. Це дуже корисно, і ви часто бачите візерунки Activator.CreateInstance(Nullable.GetUnderlyingType(type) ?? type). Це як asключове слово, перевірка амплуа, а також результат і повернення результату. Якщо ви хочете повернути базовий тип зворотного обертання, то GetGenericTypeDefinitionзробіть перевірку, а потім отримати загальний тип буде поганою ідеєю. Крім того, GetUnderlyingTypeце набагато читабельніше та запам'ятовується. Я б не заперечував, якщо я це роблю лише ~ 1000 разів.
nawfal

0

Ця версія:

  • кешування результатів відбувається швидше,
  • не вимагає зайвих змінних, наприклад, Method (T obj)
  • НЕ завершено :),
  • просто статичний загальний клас, який має одноразово обчислені поля

:

public static class IsNullable<T>
{
    private static readonly Type type = typeof(T);
    private static readonly bool is_nullable = type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>);
    public static bool Result { get { return is_nullable; } }
}

bool is_nullable = IsNullable<int?>.Result;

Я думаю, що ти відповів власноруч на цю статичну декларацію "is_nullable". Порада: оголосити об'єкти з int? (об'єкт a = (int?) 8;) і подивіться, що відбувається.
SoLaR

0

Ось що я придумав, оскільки все інше здавалося невдалим - принаймні, на PLC - Portable Class Library / .NET Core з> = C # 6

Рішення: Розширюйте статичні методи для будь-якого типу Tта Nullable<T>використовуйте той факт, що метод статичного розширення, що відповідає базовому типу, буде викликаний і має перевагу над загальним Tметодом розширення.

Для T:

public static partial class ObjectExtension
{
    public static bool IsNullable<T>(this T self)
    {
        return false;
    }
}

і для Nullable<T>

public static partial class NullableExtension
{
    public static bool IsNullable<T>(this Nullable<T> self) where T : struct
    {
        return true;
    }
}

Використання Reflection та type.IsGenericType... не працювало на моєму поточному наборі .NET Runtimes. Також не допомогла документація MSDN .

if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) {…}

Частково через те, що API Reflection був помітно змінений у .NET Core.


0

Я думаю, що ті, хто використовує запропоновані тестуванням Microsoft на користь IsGenericType, добре, але в коді для GetUnderlyingTypeMicrosoft використовується додатковий тест, щоб переконатися, що ви не пройшли визначення загального типу Nullable<>:

 public static bool IsNullableType(this Type nullableType) =>
    // instantiated generic type only                
    nullableType.IsGenericType &&
    !nullableType.IsGenericTypeDefinition &&
    Object.ReferenceEquals(nullableType.GetGenericTypeDefinition(), typeof(Nullable<>));

-1

простий спосіб зробити це:

    public static bool IsNullable(this Type type)
    {
        if (type.IsValueType) return Activator.CreateInstance(type) == null;

        return true;
    }

це мої одиничні тести і все пройшло

    IsNullable_String_ShouldReturn_True
    IsNullable_Boolean_ShouldReturn_False
    IsNullable_Enum_ShouldReturn_Fasle
    IsNullable_Nullable_ShouldReturn_True
    IsNullable_Class_ShouldReturn_True
    IsNullable_Decimal_ShouldReturn_False
    IsNullable_Byte_ShouldReturn_False
    IsNullable_KeyValuePair_ShouldReturn_False

фактичні одиничні випробування

    [TestMethod]
    public void IsNullable_String_ShouldReturn_True()
    {
        var typ = typeof(string);
        var result = typ.IsNullable();
        Assert.IsTrue(result);
    }

    [TestMethod]
    public void IsNullable_Boolean_ShouldReturn_False()
    {
        var typ = typeof(bool);
        var result = typ.IsNullable();
        Assert.IsFalse(result);
    }

    [TestMethod]
    public void IsNullable_Enum_ShouldReturn_Fasle()
    {
        var typ = typeof(System.GenericUriParserOptions);
        var result = typ.IsNullable();
        Assert.IsFalse(result);
    }

    [TestMethod]
    public void IsNullable_Nullable_ShouldReturn_True()
    {
        var typ = typeof(Nullable<bool>);
        var result = typ.IsNullable();
        Assert.IsTrue(result);
    }

    [TestMethod]
    public void IsNullable_Class_ShouldReturn_True()
    {
        var typ = typeof(TestPerson);
        var result = typ.IsNullable();
        Assert.IsTrue(result);
    }

    [TestMethod]
    public void IsNullable_Decimal_ShouldReturn_False()
    {
        var typ = typeof(decimal);
        var result = typ.IsNullable();
        Assert.IsFalse(result);
    }

    [TestMethod]
    public void IsNullable_Byte_ShouldReturn_False()
    {
        var typ = typeof(byte);
        var result = typ.IsNullable();
        Assert.IsFalse(result);
    }

    [TestMethod]
    public void IsNullable_KeyValuePair_ShouldReturn_False()
    {
        var typ = typeof(KeyValuePair<string, string>);
        var result = typ.IsNullable();
        Assert.IsFalse(result);
    }
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.