如何检查一个对象的所有属性是否为空或为null?

100
我有一个对象,让我们称之为ObjectA,该对象有10个属性,都是字符串。
var myObject = new {Property1="",Property2="",Property3="",Property4="",...}

有没有办法检查所有这些属性是否为null或空?

是否有任何内置方法可返回true或false?

如果它们中的任何一个不为null或空,则返回值应为false,如果它们全部为空,则应返回true。

我只想避免编写10个if语句来检查每个属性是否为空或null。


4
尝试使用反射。 - Ondrej Janacek
1
反射,但是要问问自己...那个数据结构是否是一个好的方法?似乎 myObject 真的只是一个数组。 - CodingIntrigue
3
在网站开发中,我有一个视图模型(搜索过滤器),当所有过滤器为空时,Linq语句会从数据库中返回所有结果。我想到了这样一个想法,如果这些过滤器从视图模型中返回为空,则不应用过滤器。但是写十个if else听起来并不好。 - akd
这个问题真的很令人困惑和模糊。您是在询问检查它们是否全部为 null?全部为空?没有为 null?没有为空?全部为 null 或空?没有为 null 或空? - Caltor
11个回答

151
您可以使用反射来完成。
bool IsAnyNullOrEmpty(object myObject)
{
    foreach(PropertyInfo pi in myObject.GetType().GetProperties())
    {
        if(pi.PropertyType == typeof(string))
        {
            string value = (string)pi.GetValue(myObject);
            if(string.IsNullOrEmpty(value))
            {
                return true;
            }
        }
    }
    return false;
}

Matthew Watson提出了一种使用LINQ的替代方案:

return myObject.GetType().GetProperties()
    .Where(pi => pi.PropertyType == typeof(string))
    .Select(pi => (string)pi.GetValue(myObject))
    .Any(value => string.IsNullOrEmpty(value));

3
如果您有需要排除的ID属性或其他内容,可以进行以下检查:if (pi.Name.Equals("InfoID") || pi.Name.Equals("EmployeeID") || pi.Name.Equals("LastUpdated")),然后使用continue跳过。 - Kremena Lalova
1
如果它们都是可空的,除了字符串之外,这是否会对其他属性类型产生影响? - Lukas
使用 LINQ 的完美想法 - M.Kasaei

21

我想你希望确保所有属性都被填写了。

更好的选择可能是在类的构造函数中进行验证,如果验证失败则抛出异常。这样,您就无法创建无效的类;捕获异常并相应处理。

Fluent验证 (http://fluentvalidation.codeplex.com) 是一个很好的框架用于进行验证。例如:

public class CustomerValidator: AbstractValidator<Customer> 
{
    public CustomerValidator()
    {
        RuleFor(customer => customer.Property1).NotNull();
        RuleFor(customer => customer.Property2).NotNull();
        RuleFor(customer => customer.Property3).NotNull();
    }
}

public class Customer
{
    public Customer(string property1, string property2, string property3)
    {
         Property1  = property1;
         Property2  = property2;
         Property3  = property3;
         new CustomerValidator().ValidateAndThrow();
    }

    public string Property1 {get; set;}
    public string Property2 {get; set;}
    public string Property3 {get; set;}
}

使用方法:

 try
 {
     var customer = new Customer("string1", "string", null);
     // logic here
 } catch (ValidationException ex)
 {
     // A validation error occured
 }

PS - 使用反射来处理这种事情只会使你的代码更难读懂。如上所示,使用验证可以明确表明您的规则;而且您可以轻松地扩展它们以包含其他规则。


18

以下代码返回如果任何属性不为 null。

  return myObject.GetType()
                 .GetProperties() //get all properties on object
                 .Select(pi => pi.GetValue(myObject)) //get value for the property
                 .Any(value => value != null); // Check if one of the values is not null, if so it returns true.

12

就给你

var instOfA = new ObjectA();
bool isAnyPropEmpty = instOfA.GetType().GetProperties()
     .Where(p => p.GetValue(instOfA) is string) // selecting only string props
     .Any(p => string.IsNullOrWhiteSpace((p.GetValue(instOfA) as string)));

这是该类的内容

class ObjectA
{
    public string A { get; set; }
    public string B { get; set; }
}

1
它说两个地方都无法解析 p.GetValue(myObj) 吗? - akd
请尝试复制粘贴我的答案。然后再复制类本身的代码并重新运行它。 - Ondrej Janacek
1
请问,如果您要给我的答案投反对票,请告诉我为什么。如果我不知道它们为什么受到反对,那么我该如何改进它们呢? - Ondrej Janacek
我没有给你的答案点踩,但是你的答案对我不起作用。我所说的对象是一个ActionResult SearchResult(MyObjectViewModel myObj) {}。 - akd
所以我的 myObj 对象有由用户填充并发送到服务器的字符串属性。然后在控制器上,我试图控制这些属性是否全部为空。 - akd
2
请编辑您的问题并添加您正在尝试的确切代码,并清楚地解释您遇到了什么错误。我发布了一个通用答案,因为您提出了一个通用问题。您的问题中没有关于视图和控制器的内容。 - Ondrej Janacek

6

一种稍微不同的表达方式是使用Linq来判断一个对象的所有字符串属性是否都非空非空串:

public static bool AllStringPropertyValuesAreNonEmpty(object myObject)
{
    var allStringPropertyValues = 
        from   property in myObject.GetType().GetProperties()
        where  property.PropertyType == typeof(string) && property.CanRead
        select (string) property.GetValue(myObject);

    return allStringPropertyValues.All(value => !string.IsNullOrEmpty(value));
}

这个可以运行,但是如果对象有属性ID,我能获取那些属性为空或者为null的ID吗? - Shaiju T
@stom 你可以添加过滤器来检查“名称”和值。 - Matthew Watson
谢谢,我不明白你指的是哪些过滤器,但我会进行一些研究。 - Shaiju T
请记得给属性添加 get; set;,否则 GetProperties 方法将无法正常工作。参见 https://dev59.com/L2sz5IYBdhLWcg3wiISe。 - yu yang Jian

3

仅检查所有属性是否为空:

bool allPropertiesNull = !myObject.GetType().GetProperties().Any(prop => prop == null);

1
这实际上告诉您所有属性是否都不为空。 - Caltor

3

注意,如果您拥有一个数据结构层次,并且想要测试该层次中的所有内容,则可以使用递归方法。以下是一个快速示例:

static bool AnyNullOrEmpty(object obj) {
  return obj == null
      || obj.ToString() == ""
      || obj.GetType().GetProperties().Any(prop => AnyNullOrEmpty(prop.GetValue(obj)));
}

2
您可以使用反射和扩展方法来完成这个任务。
using System.Reflection;
public static class ExtensionMethods
{
    public static bool StringPropertiesEmpty(this object value)
    {
        foreach (PropertyInfo objProp in value.GetType().GetProperties())
        {
            if (objProp.CanRead)
            {
                object val = objProp.GetValue(value, null);
                if (val.GetType() == typeof(string))
                {
                    if (val == "" || val == null)
                    {
                        return true;
                    }
                }
            }
        }
        return false;
    }
}

然后将其用于具有字符串属性的任何对象。
test obj = new test();
if (obj.StringPropertiesEmpty() == true)
{
    // some of these string properties are empty or null
}

0

不,我认为没有一种方法可以完全做到这一点。

最好编写一个简单的方法,它接受您的对象并返回true或false。

或者,如果属性都相同,并且您只想解析它们并查找单个null或empty,也许某种字符串集合适合您?


0
您可以尝试以下查询:
如果对象是"referenceKey"(其中一些属性可能为空)
referenceKey.GetType().GetProperties().Where(x => x.GetValue(referenceKey) == null)

我需要计算属性中值不为空的数量,因此我使用了以下查询:

 var countProvidedReferenceKeys = referenceKey.GetType().GetProperties().Where(x => x.GetValue(referenceKey) != null).Count();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接