我如何知道 lambda 表达式何时为空

2023-12-24

我需要以编程方式检查 lambda 表达式中的嵌套属性/函数结果是否为 null。问题在于 null 可能位于任何嵌套子属性中。

例子。功能是:

 public static bool HasNull<T, Y>(this T someType, Expression<Func<T, Y>> input)
    {
      //Determine if expression has a null property
    }  

Use:

person.HasNull(d=>d.addressdetails.Street)
person.HasNull(d=>d.addressdetails[1].Street)
person.HasNull(d=>d.addressdetails.FirstOrDefault().Street)
person.HasNull(d=>d.InvoiceList.FirstOrDefault().Product.Name)

在任何示例中,地址详细信息、街道、发票列表、产品或名称都可以为空。如果我尝试调用该函数并且某些嵌套属性为空,则代码将引发异常。

重要提示:我不想为此使用 try catch,因为这对于调试性能来说是灾难性的。

这种方法的原因是快速检查值,同时我不想忘记任何空值并因此导致异常。这对于报告解决方案和网格来说非常方便,其中报告上的空值只能显示为空并且没有进一步的业务规则。

相关帖子:当抛出和捕获异常时,不要停止调试器 https://stackoverflow.com/questions/1420390/dont-stop-debugger-at-that-exception-when-its-thrown-and-caught


这是可能的,但我不确定我会推荐它。您可能会发现以下内容很有用:它不返回布尔值,而是返回表达式的叶值(如果可能)(无空引用)。

public static class Dereferencer
{
    private static readonly MethodInfo safeDereferenceMethodInfo 
        = typeof (Dereferencer).GetMethod("SafeDereferenceHelper", BindingFlags.NonPublic| BindingFlags.Static);


    private static TMember SafeDereferenceHelper<TTarget, TMember>(TTarget target,
                                                            Func<TTarget, TMember> walker)
    {
        return target == null ? default(TMember) : walker(target);
    }

    public static TMember SafeDereference<TTarget, TMember>(this TTarget target, Expression<Func<TTarget, TMember>> expression)
    {
        var lambdaExpression = expression as LambdaExpression;
        if (lambdaExpression == null)
            return default(TMember);

        var methodCalls = new Queue<MethodCallExpression>();
        VisitExpression(expression.Body, methodCalls);
        var callChain = methodCalls.Count == 0 ? expression.Body : CombineMethodCalls(methodCalls);
        var exp = Expression.Lambda(typeof (Func<TTarget, TMember>), callChain, lambdaExpression.Parameters);
        var safeEvaluator = (Func<TTarget, TMember>) exp.Compile();

        return safeEvaluator(target);
    }

    private static Expression CombineMethodCalls(Queue<MethodCallExpression> methodCallExpressions)
    {
        var callChain = methodCallExpressions.Dequeue();
        if (methodCallExpressions.Count == 0)
            return callChain;

        return Expression.Call(callChain.Method, 
                               CombineMethodCalls(methodCallExpressions), 
                               callChain.Arguments[1]);
    }

    private static MethodCallExpression GenerateSafeDereferenceCall(Type targetType,
                                                                    Type memberType,
                                                                    Expression target,
                                                                    Func<ParameterExpression, Expression> bodyBuilder)
    {
        var methodInfo = safeDereferenceMethodInfo.MakeGenericMethod(targetType, memberType);
        var lambdaType = typeof (Func<,>).MakeGenericType(targetType, memberType);
        var lambdaParameterName = targetType.Name.ToLower();
        var lambdaParameter = Expression.Parameter(targetType, lambdaParameterName);
        var lambda = Expression.Lambda(lambdaType, bodyBuilder(lambdaParameter), lambdaParameter);
        return Expression.Call(methodInfo, target, lambda);
    }

    private static void VisitExpression(Expression expression, 
                                        Queue<MethodCallExpression> methodCallsQueue)
    {
        switch (expression.NodeType)
        {
            case ExpressionType.MemberAccess:
                VisitMemberExpression((MemberExpression) expression, methodCallsQueue);
                break;
            case ExpressionType.Call:
                VisitMethodCallExpression((MethodCallExpression) expression, methodCallsQueue);
                break;
        }
    }

    private static void VisitMemberExpression(MemberExpression expression, 
                                              Queue<MethodCallExpression> methodCallsQueue)
    {
        var call = GenerateSafeDereferenceCall(expression.Expression.Type,
                                               expression.Type,
                                               expression.Expression,
                                               p => Expression.PropertyOrField(p, expression.Member.Name));

        methodCallsQueue.Enqueue(call);
        VisitExpression(expression.Expression, methodCallsQueue);
    }

    private static void VisitMethodCallExpression(MethodCallExpression expression, 
                                                  Queue<MethodCallExpression> methodCallsQueue)
    {
        var call = GenerateSafeDereferenceCall(expression.Object.Type,
                                               expression.Type,
                                               expression.Object,
                                               p => Expression.Call(p, expression.Method, expression.Arguments));

        methodCallsQueue.Enqueue(call);
        VisitExpression(expression.Object, methodCallsQueue);
    }
}

您可以这样使用它:

var street = person.SafeDereference(d=>d.addressdetails.Street);
street = person.SafeDereference(d=>d.addressdetails[1].Street);
street = person.SafeDereference(d=>d.addressdetails.FirstOrDefault().Street);
var name = person.SafeDereference(d=>d.InvoiceList.FirstOrDefault().Product.Name);

警告:这还没有经过充分测试,它should使用方法和属性,但可能不使用表达式内的扩展方法。

编辑:好的,它现在无法处理扩展方法(例如FirstOrDefault)但仍然可以调整解决方案。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

我如何知道 lambda 表达式何时为空 的相关文章

  • 部署 MVC4 项目时出错:找不到文件或程序集

    过去 我只需使用 Visual Studio 2012 发布到 AWS 菜单项即可部署我的 MVC4 网站 到 AWS Elastic Beanstalk 现在 程序可以在本地编译并运行 但无法部署 从消息来看 它似乎正在寻找不在当前部署的
  • boost::multi_index_container 复合键中的 equal_range 与比较运算符

    我正在尝试从多索引容器查询结果 其中值类型是三个元素的结构 第一个值已给出 但第二个和第三个值必须大于或小于查询参数 经过搜索后 我发现必须实现自定义密钥提取器 并且这里的一些链接建议相同 但我无法实现它 boost multi index
  • 创建 DirectoryEntry 实例以供测试使用

    我正在尝试创建 DirectoryEntry 的实例 以便可以使用它来测试将传递 DirectoryEntry 的一些代码 然而 尽管进行了很多尝试 我还是找不到实例化 DE 并初始化它的 PropertyCollection 的方法 我有
  • C++:无法使用scoped_allocator_adaptor传播polymorphic_allocator

    我有一个vector
  • 为什么禁止在 constexpr 函数中使用 goto?

    C 14 对你能做什么和不能做什么有规则constexpr功能 其中一些 没有asm 没有静态变量 看起来相当合理 但标准也不允许goto in constexpr功能 即使它允许其他控制流机制 这种区别背后的原因是什么 我以为我们已经过去
  • 当 Cortex-M3 出现硬故障时如何保留堆栈跟踪?

    使用以下设置 基于 Cortex M3 的 C gcc arm 交叉工具链 https launchpad net gcc arm embedded 使用 C 和 C FreeRtos 7 5 3 日食月神 Segger Jlink 与 J
  • .Net Core / 控制台应用程序 / 配置 / XML

    我第一次尝试使用新的 ConfigurationBuilder 和选项模式进入 Net Core 库 这里有很多很好的例子 https docs asp net en latest fundamentals configuration ht
  • Windows 10 中 Qt 桌面应用程序的缩放不当

    我正在为 Windows 10 编写一个简单的 Qt Widgets Gui 应用程序 我使用的是 Qt 5 6 0 beta 版本 我遇到的问题是它根本无法缩放到我的 Surfacebook 的屏幕上 这有点难以判断 因为 SO 缩放了图
  • .NET 选项将视频文件流式传输为网络摄像头图像

    我有兴趣开发一个应用程序 它允许我从 xml 构建视频列表 包含视频标题 持续时间等 并将该列表作为我的网络摄像头流播放 这意味着 如果我要访问 ustream tv 或在实时通讯软件上激活我的网络摄像头 我的视频播放列表将注册为我的活动网
  • AccessViolationException 未处理

    我正在尝试使用史蒂夫 桑德森的博客文章 http blog stevensanderson com 2010 01 28 editing a variable length list aspnet mvc 2 style 为了在我的 ASP
  • 什么是 C 语言的高效工作流程? - Makefile + bash脚本

    我正在开发我的第一个项目 该项目将跨越多个 C 文件 对于我的前几个练习程序 我只是在中编写了我的代码main c并使用编译gcc main c o main 当我学习时 这对我有用 现在 我正在独自开展一个更大的项目 我想继续自己进行编译
  • 将日期参数传递给对 MVC 操作的 ajax 调用的安全方法

    我有一个 MVC 操作 它的参数之一是DateTime如果我通过 17 07 2012 它会抛出一个异常 指出参数为空但不能有空值 但如果我通过01 07 2012它被解析为Jan 07 2012 我将日期传递给 ajax 调用DD MM
  • char指针或char变量的默认值是什么[重复]

    这个问题在这里已经有答案了 下面是我尝试打印 char 变量和指针的默认值 值的代码 但无法在控制台上看到它 它是否有默认值或只是无法读取 ASCII 范围 include
  • ListDictionary 类是否有通用替代方案?

    我正在查看一些示例代码 其中他们使用了ListDictionary对象来存储少量数据 大约 5 10 个对象左右 但这个数字可能会随着时间的推移而改变 我使用此类的唯一问题是 与我所做的其他所有事情不同 它不是通用的 这意味着 如果我在这里
  • 方法参数内的变量赋值

    我刚刚发现 通过发现错误 你可以这样做 string s 3 int i int TryParse s hello out i returns false 使用赋值的返回值是否合法 Obviously i is but is this th
  • 如何使用 ReactiveList 以便在添加新项目时更新 UI

    我正在创建一个带有列表的 Xamarin Forms 应用程序 itemSource 是一个reactiveList 但是 向列表添加新项目不会更新 UI 这样做的正确方法是什么 列表定义 listView new ListView var
  • 更改显示的 DPI 缩放大小使 Qt 应用程序的字体大小渲染得更大

    我使用 Qt 创建了一些 GUI 应用程序 我的 GUI 应用程序包含按钮和单选按钮等控件 当我运行应用程序时 按钮内的按钮和字体看起来正常 当我将显示器的 DPI 缩放大小从 100 更改为 150 或 200 时 无论分辨率如何 控件的
  • C++ 成员函数中的“if (!this)”有多糟糕?

    如果我遇到旧代码if this return 在应用程序中 这种风险有多严重 它是一个危险的定时炸弹 需要立即在应用程序范围内进行搜索和销毁工作 还是更像是一种可以悄悄留在原处的代码气味 我不打算writing当然 执行此操作的代码 相反
  • 将 viewbag 从操作控制器传递到部分视图

    我有一个带有部分视图的 mvc 视图 控制器中有一个 ActionResult 方法 它将返回 PartialView 因此 我需要将 ViewBag 数据从 ActionResult 方法传递到 Partial View 这是我的控制器
  • 不同类型的指针可以互相分配吗?

    考虑到 T1 p1 T2 p2 我们可以将 p1 分配给 p2 或反之亦然吗 如果是这样 是否可以不使用强制转换来完成 或者我们必须使用强制转换 首先 让我们考虑不进行强制转换的分配 C 2018 6 5 16 1 1 列出了简单赋值的约束

随机推荐

  • 为什么Java能够将0xff000000存储为int?

    Java 中整数的最大值是 2147483647 因为 Java 整数是有符号的 对吗 0xff000000 的数值为 4278190080 但我看到的 Java 代码是这样的 int ALPHA MASK 0xff000000 有人可以启
  • PHP中如何删除点后的所有数字

    示例 1 123 gt 1 1 999 gt 1 thanks y 1 235251 x int y echo x will echo 1 Edit 使用显式转换为 int 是实现此目的的最有效方法 另外 转换为 int 会截断 后面的数字
  • 使用 cmd.exe 将长文件名转换为短文件名 (8.3)

    我正在尝试在 Windows 上将长文件名转换为短文件名 8 3 带有命令行参数的批处理文件按预期工作 短蝙蝠 echo OFF echo s1 calling short bat C Documents and Settings User
  • 在嵌套 Lambda 中捕获 Lambda 的静态

    In 这个答案 https stackoverflow com a 33282441 2642059我使用这段代码 std vector
  • 尝试计算两个时间之间的差,不会相减

    我的程序所做的是 它首先打印当前时间 然后用户按 Enter 键 然后它再次打印出时间并计算用户等待按 Enter 键的时间 我没时间做减法 我从 stackoverflow 中的另一个问题中得到了打印当地时间的代码 include
  • 在 switch 语句中使用字符串集合

    我正在努力寻找解决这个问题的方法 这是我的示例代码 class Program private string Command private static string Commands ComandOne CommandTwo Comma
  • jQuery 函数 $(function()) 多次调用 $(function()) 时的执行顺序

    代码如下 window document ready function window alert alert 1 function window alert alert 2 function window alert alert 3
  • 应该 rspec 匹配器 :on => :create

    我正在使用一些 Shoulda rspec 匹配器来测试我的模型 其中之一是 describe Issue do it should not allow value test for priority end 我的问题是模型中的验证如下所示
  • C# 中的条件运算符和返回类型[重复]

    这个问题在这里已经有答案了 可能的重复 为什么 null 需要在这里进行显式类型转换 https stackoverflow com questions 2608878 why does null need an explicit type
  • 使用 UI 的 Airflow s3 连接

    我一直在尝试使用 Airflow 来安排 DAG 其中一个 DAG 包含一项从 s3 存储桶加载数据的任务 出于上述目的 我需要设置 s3 连接 但气流提供的 UI 并不那么直观 http pythonhosted org airflow
  • 哪种算法是查找素数最快的算法?

    使用 C 找出素数最快的算法是什么 我已经使用了 sieve 算法 但我仍然希望它更快 非常快的实施阿特金筛 http en wikipedia org wiki Sieve of Atkin是丹 伯恩斯坦的primegen http cr
  • 在 Ruby on Rails 的模型中使用“current_user”

    我正在使用 Devise 它在助手中提供了 current user 方法 以便我可以在视图和控制器中使用 但是现在我想访问模型中的 current user 方法 这是我现在控制器中的内容 def create set email add
  • 为什么 `Array(0,1,2) == Array(0,1,2)` 没有返回预期结果?

    据我了解 Scala 的 定义两个对象的自然平等 我期望Array 0 1 2 Array 0 1 2 比较自然平等 例如 检查与另一个数组的相应元素比较时数组的所有元素是否返回 true 人们告诉我 Scala 的Array只是一个Jav
  • 为什么 C# 中的类型推断不适用于动态对象和泛型方法?

    我正在开发一个项目 该项目使用 C 泛型与动态关键字相结合来实现一个简单的 prototxt Caffe 文件解析器 该解析器基于 Google protocol buffer 项目的 proto2 语法 解析器使用非常简单的语法来读取 p
  • 将域模型映射到视图模型

    我从一个非常相似的点开始 领域实体 DTO 和视图模型 https stackoverflow com questions 5330172 domain entities dto and view models 建议使用 DTO 在域模型和
  • 如何使用相对路径访问不属于任何项目/程序集的图像[重复]

    这个问题已经存在了 我正在为 帝国时代 2 DE 制作一个模组 我的目标是从新 UI 的目录访问旧的纹理文件 文件结构如下 C Program Files x86 Steam steamapps common AoE2DE 是包含exe的游
  • 重构 JSON 数据

    目前我有一个 json 文件 其中存储了多个数据 如下所示 name Adelphi University supp Yes E WS ed u00a0 online 40 ea 12 1 mid No rd Rolling recs Ye
  • Doctrine 2.0 引导程序?

    好的 我已经在文件夹层次结构中找到了 Doctrine php 文件 如下所示 includes Setup php Doctrine Common DBAL ORM Symfony Doctrine php 我的 setup php 有以
  • 在课堂上使用碰撞列表

    我创建了一个类来创建矩形并将它们放入列表中 我不想让它们碰撞 所以我使用 collidelist 但它不起作用 矩形仍在碰撞 我还希望矩形在击中特定点时向下移动并更改 x 位置 我可以做到这一点 但我不确定它是否会阻止碰撞列表工作 请查看下
  • 我如何知道 lambda 表达式何时为空

    我需要以编程方式检查 lambda 表达式中的嵌套属性 函数结果是否为 null 问题在于 null 可能位于任何嵌套子属性中 例子 功能是 public static bool HasNull