正确区分bool?和布尔在 C#

Correctly distinguish between bool? and bool in C#

我想知道一个变量是简单的 bool 还是 Nullable<bool>

好像

if(val is Nullable<bool>)

returns boolNullable<bool> 变量和

都为真
if(val is bool)

对于 boolNullable<bool> 也 returns 正确。

基本上,我感兴趣的是找出一个简单的 bool 变量是否 true OR 如果 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(更具体地说,找出任何不为 null 的值并将它们保存在 List<string> ).然而,当试图区分我的对象中的 boolbool? 类型时(第二个 Where 语句),这会在 lambda 表达式中带来复杂性。

此外,由于该对象也包含一些字符串类型,我试图在我的第一个 .Where 语句中排除那些(我目前可能没有做对,因为它似乎不是在职的)。但我的主要目标是区分 boolbool? 类型。

这是对初始问题的回答 - 忽略它。

当您 "box" 一个可为 null 的值(所以您将其放在 object 中)时,它会转换为其基础类型(在您的情况下为 bool)或 null...所以如果你有

bool? value = true;
object value2 = value; 

现在value2.GetType() == typeof(bool)

有一种简单的方法可以检查一个变量是声明为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();

获取 class 个实例值的代码:

// 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);
typeof(InstViewModel).GetProperties()
  .Select(prop => prop.GetValue(ivm, null))

此时,您有一个 object 类型的序列。该序列的每个元素都是一个对象,可以是以下之一:

  1. 引用类型的实例。
  2. 值类型的盒装实例。
  3. null.

null 情况的发生可能是因为 属性 的空值是引用类型,或者 属性 的空值是可空值类型;这里无法区分。同样,无法区分来自 bool 值的盒装 bool 或来自 bool? 值的盒装 bool 之间的区别。

您需要检查 属性 的类型,而不是 属性 的值:

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

但是如果只过滤到 boolbool? 那么:

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

试试这个:

((bool?)val).HasValue

这将 return true,如果 valbool 如果 valbool? 哪个值不是 null.

另一方面,

!((bool?)val).HasValue

只会 return true 如果 val 是 bool? 它的值是 null.

这个测试对你来说还不够吗?

根据你的问题

Basically, I am interested in finding out if a simple bool variable is true OR if a Nullable variable is not null.

  • 判断一个简单的 boolVariable 是否为真

     if(boolVariable){
          //bool variable, not nullable
     }
    
  • 判断您的 nullableVariable 是否不为 null

     if(nullableVariable.HasValue){
         //a nullable variable is not null
     }
    
  • 判断可空布尔变量是否为真or/and不为空,使用??运算符

    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*/
    }

试试这个

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();

您可以在计算布尔值和可为 null 的布尔值属性之前区分它们。那么就无需担心它们的计算结果是 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();

这会为您提供所需的列表。