Правильно отличить bool? и bool в С#

Я пытаюсь выяснить, является ли переменная простой: bool или Nullable<bool>.

Кажется, что

if(val is Nullable<bool>)

возвращает true для переменных bool и Nullable<bool> и

if(val is bool)

также возвращает true для bool и Nullable<bool>.

В принципе, мне интересно узнать, является ли простая переменная bool истиной ИЛИ, если переменная Nullable<bool> не равна нулю.

Каким образом это сделать?

Вот полный код:

List<string> values = typeof(InstViewModel).GetProperties()
                          .Where(prop => prop != "SubCollection" && prop != "ID" && prop != "Name" && prop != "Level")
                          .Select(prop => prop.GetValue(ivm, null))
                          .Where(val => val != null && (val.GetType() != typeof(bool) || (bool)val == true))      //here I'm trying to check if val is bool and true or if bool? and not null
                          .Select(val => val.ToString())
                          .Where(str => str.Length > 0)
                          .ToList();

Объект InstViewModel:

 public class InstViewModel
    {
        public string SubCollection { get; set; }
        public string ID { get; set; }
        public string Name { get; set; }
        public string Level { get; set; }
        public bool Uk { get; set; }
        public bool Eu { get; set; }
        public bool Os { get; set; }
        public Nullable<bool> Mobiles { get; set; }
        public Nullable<bool> Landlines { get; set; }
        public Nullable<bool> UkNrs { get; set; }
        public Nullable<bool> IntNrs { get; set; }
}

Точка моего кода здесь заключается в том, чтобы узнать, являются ли все значения объекта null (точнее, для определения любых значений, которые не являются нулевыми, и сохраняют их в List<string>). Это представляет собой усложнение в выражении лямбда, однако, при попытке различить типы bool и bool? в моем объекте (второй оператор Where).

Кроме того, поскольку объект также содержит некоторые типы строк, я пытаюсь исключить их в первом операторе .Where (который, вероятно, сейчас не работает правильно, поскольку он, похоже, не работает). Но моя главная цель - различать типы bool и bool?.

Ответы

Ответ 1

Код для получения значений экземпляра класса:

// create class instance
InstViewModel model = new InstViewModel()
{
    Uk = true,
    UkNrs = false,
};

// check all boolean fields are false or null
bool isAllNullOrFalse = (from property in typeof(InstViewModel).GetProperties()
                         let type = property.PropertyType
                         let isBool = type == typeof(bool)
                         where isBool || type == typeof(bool?)
                         let value = property.GetValue(model)
                         select value == null || (isBool && bool.Equals(value, false))).All(e => e);

Console.WriteLine("All values are null or false = {0}", isAllNullOrFalse);

Ответ 2

Существует простой способ проверить, объявлена ​​ли переменная как T или T?:

private static bool IsNullable<T>(T val)
{
    return false;
}

private static bool IsNullable<T>(T? val)
    where T : struct
{
    return true;
}

Использование:

bool? val = false;

if (IsNullable(val))
{
    ...
}

ИЗМЕНИТЬ
Попробуйте следующий код для отредактированного вопроса:

var boolProps = typeof (InstViewModel).GetProperties()
    .Where(prop => prop.PropertyType == typeof(bool))
    .Select(prop => (bool)prop.GetValue(ivm, null))
    .Select(v => v ? v.ToString() : String.Empty);

var nullableBoolProps = typeof(InstViewModel).GetProperties()
    .Where(prop => prop.PropertyType == typeof(bool?))
    .Select(prop => (bool?)prop.GetValue(ivm, null))
    .Select(v => v.HasValue ? v.ToString() : String.Empty);

List<string> values = boolProps.Concat(nullableBoolProps)
              .Where(str => str.Length != 0)
              .ToList();

Ответ 3

typeof(InstViewModel).GetProperties()
  .Select(prop => prop.GetValue(ivm, null))

На этом этапе у вас есть последовательность типов object. Каждый элемент этой последовательности будет объектом, который может быть одним из:

  • Пример ссылочного типа.
  • Вставной экземпляр типа значения.
  • null.

Случай null может произойти либо потому, что у вас есть нулевое значение для свойства, которое имеет ссылочный тип, либо значение null для свойства, которое является типом значений с нулевым значением; нет никакого способа сказать разницу здесь. Точно так же нет способа рассказать разницу между коробкой bool, которая исходила из значения bool или в коробке bool, которая была получена из значения bool?.

Вам нужно изучить тип свойства, а не значение свойства:

isNullableProperty = property.PropertyType.IsGenericType
  && property.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>);

Но просто отфильтровать только bool и bool?, затем:

typeof(InstViewModel).GetProperties()
  .Where(
     prop => prop.PropertyType == typeof(bool)
     || prop.PropertyType == typeof(bool?))

Ответ 4

Вы можете отличить логические и обнуляемые логические свойства перед их оценкой. Тогда нет необходимости беспокоиться о том, оценивают ли они значение bool или Nullable<bool>:

var nullableBooleanProperties = typeof(InstViewModel).Where(prop => prop.PropertyType == typeof(bool?));

Затем вы можете просто записать их в список строк:

var values = nullableBooleanProperties.Select(prop => prop.GetValue(ivm)).Where(val => val != null).Select(val => val.ToString());

Объединяя их вместе, получаем:

var values = typeof(InstViewModel).Where(prop => prop.PropertyType == typeof(bool?))
    .Select(prop => prop.GetValue(ivm)).Where(val => val != null)
    .Select(val => val.ToString())
    .ToList();

который дает вам список, который вы ищете.

Ответ 5

Это ответ на исходный вопрос - игнорируйте это.

Когда вы "вставляете" значение с нулевым значением (поэтому вы помещаете его в object), оно преобразуется в его базовом типе (bool в вашем случае) или в null... Итак, если у вас есть

bool? value = true;
object value2 = value; 

теперь value2.GetType() == typeof(bool)

Ответ 6

По вашему вопросу

В принципе, мне интересно узнать, истинна ли простая переменная bool или если переменная Nullable не равна null.

  • чтобы узнать, истинна ли простая boolVariable

     if(boolVariable){
          //bool variable, not nullable
     }
    
  • чтобы узнать, не является ли ваш nullableVariable нулевым

     if(nullableVariable.HasValue){
         //a nullable variable is not null
     }
    
  • чтобы указать, является ли переменная bool переменной null равной true или/или не равна нулю, используйте оператор ??

    if(variable??false){
       //then I'm sure that this is not null and has value=true
    }
    

Итак, в окончательном варианте вы можете использовать следующий код для переменных с нулевым значением bool и bool

     if(variables!=null &&variables!=false){/*This may give a warning message but it works*/}

или

   if(((bool?)variable)??false){
      /*variable is not null and is true*/
    }

Ответ 7

Попробуйте следующее:

((bool?)val).HasValue

Это вернет true, если val является bool или, если val является bool?, значение которого не равно null.

С другой стороны,

!((bool?)val).HasValue

будет возвращать только true, если val bool? и его значение null.

Не будет ли этого теста достаточно в вашем случае?

Ответ 8

Попробуйте это

List<string> values = typeof(InstViewModel).GetProperties()
    .Select(prop => new { N = prop.Name, T = prop.PropertyType, V = prop.GetValue(ivm, null) })
    .Where(prop => prop.N != "SubCollection" && prop.N != "ID" && prop.N != "Name" && prop.N != "Level")
    .Where(val => (val.V != null && val.T.IsAssignableFrom(typeof(Nullable<bool>))) || Convert.ToBoolean(val.V))                    
    .Select(val => val.V.ToString())
    .Where(str => str.Length > 0)
    .ToList();