【问题标题】:C# elegant way to check if all shallow properties are null (or any property is not null)C# 检查所有浅层属性是否为空(或任何属性不为空)的优雅方法
【发布时间】:2014-09-30 18:32:04
【问题描述】:

当我读到这个问题时 Deep Null checking, is there a better way?

还有这个

C# elegant way to check if a property's property is null

假设我要检查所有属性是否不为空,或者是否有任何属性不为空。(浅属性)

SearchCriteria 对象:

Keyword (Searches Name and Description) != null ||
SectorId != null ||
IndustryId != null ||
HasOption != null ||
HasFutures != null ||
30 properties to go...

正如我们所见,语法有点难以阅读。我想要类似的东西

SearchCriteria
.Has(criteria => criteria.Keywork)
.Has(criteria => criteria.SectorId)
.Has(criteria => criteria.HasOption)
.etc

(如果我们希望以上所有属性都不为空)

SearchCriteria
.Has(criteria => criteria.Keywork).Or()
.Has(criteria => criteria.SectorId).Or()
.Has(criteria => criteria.HasOption).Or()
.etc

(如果我们想要任何属性不为空)

SearchCriteria
.Has(criteria => criteria.Keywork).Or()
.Has(criteria => criteria.SectorId)
.Has(criteria => criteria.HasOption)
.etc

(如果我们希望关键字 SectorId 有值并且 HasOption 有值。

那么,我们在 codeplex 上是否有任何现成的项目?或者任何可以结合深空检查和浅空检查的优雅方法?

【问题讨论】:

  • 如果它是一个 blittable struct 你可以检查内存是否归零,但我不确定这算不算“优雅”;它已从 C# 中删除,足以算作比您拥有的更丑陋。
  • @JonHanna 它还取决于像 int foo 这样具有值 0 的字段是否应该像 null 一样
  • 我建议您阅读此内容...blogs.encodo.ch/news/view_article.php?id=167 优雅代码 vs 简洁代码 “聪明是美妙的,但您最终可能会严重限制愿意或能够从事此工作的人数代码。”
  • @MarcGravell 您可以检查相关八位位组的适当子集,但这只会增加所说的丑陋。
  • @PaulZahra:给文章投 1 票,很有帮助。有时代码的语义不是我们所需要的。

标签: c#


【解决方案1】:

坦率地说,我会坚持使用涉及||&&== null!= null 的简单版本。它直接有效,并允许立即短路。如果您打算这样做lots,您也许可以编写一个使用元编程(ExpressionILGenerator 可能)的实用程序类来为每个类型创建一个优化的方法来检查所有属性,然后:

if(MyHelper.AllNull(obj)) ... // note this is probably actually generic

完整示例:

using System;
using System.Linq.Expressions;
using System.Reflection;

static class Program
{
    static void Main()
    {
        bool x = MyHelper.AnyNull(new Foo { }); // true
        bool y = MyHelper.AnyNull(new Foo { X = "" }); // false
    }
}
class Foo
{
    public string X { get; set; }
    public int Y { get; set; }
}
static class MyHelper
{
    public static bool AnyNull<T>(T obj)
    {
        return Cache<T>.AnyNull(obj);
    }
    static class Cache<T>
    {
        public static readonly Func<T, bool> AnyNull;

        static Cache()
        {
            var props = typeof(T).GetProperties(
                BindingFlags.Instance | BindingFlags.Public);

            var param = Expression.Parameter(typeof(T), "obj");
            Expression body = null;

            foreach(var prop in props)
            {
                if (!prop.CanRead) continue;

                if(prop.PropertyType.IsValueType)
                {
                    Type underlyingType = Nullable.GetUnderlyingType(
                                              prop.PropertyType);
                    if (underlyingType == null) continue; // cannot be null

                    // TODO: handle Nullable<T>
                }
                else
                {
                    Expression check = Expression.Equal(
                        Expression.Property(param, prop),
                        Expression.Constant(null, prop.PropertyType));
                    body = body == null ? check : Expression.OrElse(body, check);
                }
            }
            if (body == null) AnyNull = x => false; // or true?
            else
            {
                AnyNull = Expression.Lambda<Func<T, bool>>(body, param).Compile();
            }
        }
    }
}

【讨论】:

  • 我想知道这是否有时是使用 |&amp;||&amp;&amp; 更有效的情况之一,因为避免分支的好处可以超过从短路中获益。短路方法将是默认情况下在分析显示之前执行的方法,因为它在 99% 的情况下效率更高,但考虑起来很有趣。
  • @MarcGravell:我对你的回答很感兴趣。但是,我更喜欢只检查具有更灵活语法的指定属性,就像上面的最后一个伪代码一样。我确实同意“它直接有效,并允许立即短路。”
【解决方案2】:

虽然我确实支持 Marc Gravell 的回答,只是将其完整地写出来,但如果您坚持不重复 != null,则不需要创建任何自定义方法。 LINQ 方法已经可以做你想做的事,例如:

new[] { SearchCriteria }.SelectMany(criteria => new object[] {
  criteria.Keywork,
  criteria.SectorId,
  criteria.HasOption,
  ...
}).Any(p => p != null)

为了还涵盖SearchCriteria 本身可能是null 的情况,您可以使用

new[] { SearchCriteria }.Where(criteria => criteria != null).SelectMany(...

【讨论】:

  • 一个简单的检查需要大量的分配......它依赖于你记住在多个地方维护代码
  • @MarcGravell 同意大量分配,但我阅读问题的方式是,OP 不一定对检查 all 属性感兴趣,而只对指定的属性感兴趣特性。 OP 的建议语法也明确地写出属性。
猜你喜欢
  • 2011-03-28
  • 1970-01-01
  • 2014-05-06
  • 1970-01-01
  • 2015-08-23
  • 1970-01-01
  • 2017-12-26
  • 1970-01-01
  • 2014-07-11
相关资源
最近更新 更多