前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >C#10 新特性 [调用方参数表达式] 解决了我七年前的困惑

C#10 新特性 [调用方参数表达式] 解决了我七年前的困惑

作者头像
独立观察员
发布2022-12-06 19:10:55
3520
发布2022-12-06 19:10:55
举报

C#10 新特性 [调用方参数表达式] 解决了我七年前的困惑

目录

一、问题

二、转机

三、实践

1、演示输出各种形式的参数表达式

2、参数不符合条件时抛出异常

3、获取调用扩展方法的表达式

四、结语

独立观察员 2022 年 2 月 13 日

一、问题

时间拉回到 2015 年,那年 3 月,我还没有毕业,不过已经在公司里实习了,从大三暑假开始,到那时候,已经快实习一年了(毕业后才能转正)。对于工作还是比较满意的,九点多上班(看班车什么时候到),十一点可以吃午饭,吃完饭周边散个步,然后回公司午休,下午基本坐 5 点四十 的班车回家,双休;当时组里的小伙伴们气氛也比较好,组长也比较好,我们主要负责公司内部二十多个 OA 系统(全公司一两千人),任务安排得也不是很紧;本来大学学的是 Java,公选课学了 C# 就爱上了,实习用的是现在早已过时的 Webform,当然还有 SQL;实习嘛,经常也是边学边做,经常在网上找解决方案,用麦库记事(已倒闭)做笔记,还有用问答网站进行提问,用得比较多的就是待会儿要出场的 “思否”,偶尔用的还有昙花一现的 “德问”。

当时有一个业务,具体的忘了,只记得用到了反射,当时为了写更少的代码,想要在方法中获取调用者传参时的实参的变量名,不知道怎么弄,于是在 segmentfault.com(思否)网站上提了这么一个问题 ——“C# 如何通过形参获得实参的名字?”(https://segmentfault.com/q/1010000002592470):

经过一番讨论与思考,当时我妥协了,认识到这是不可能实现的:

二、转机

直到昨天看到有人转载了一篇 微软中国 MSDN 的公众号文章《C# 10 的新特性》,在最后部分写了这么一段(灰色的原文链接有误,后面会给出正确的):

当看到下图框出的字符 b 时,我的思绪一下被拉到了七年前,这不就是我当时说服了自己把它当作不可能的事吗,现在竟然变成了可能!只能说,微软 NB!

而且,上图没有框出的另外两个例子还展示了这个功能更强大的地方 —— 不光是形参名称(或者应该叫字面量?),任何表达式它都能原样获取,比如 “true” 和 “a > 5”。

那么这个强大的功能叫什么名字呢?它就是 CallerArgumentExpressionAttribute,可以称之为 “调用方参数表达式特性”。上面公众号文章截图中的参考链接有误,正确的应该是这个 ——https://docs.microsoft.com/zh-cn/dotnet/csharp/language-reference/attributes/caller-information#argument-expressions :

可以看到它也是在 System.Runtime.CompilerServices 命名空间中,相当于扩充了原先的调用方信息,之前的调用方信息有三项,分别是 文件路径、行号、方法名,现在新增了参数表达式。关于旧的调用方信息三巨头的使用,可以参考我之前的文章《C# 在自定义的控制台输出重定向类中整合调用方信息》。

三、实践

下面开始实践,例子都来源于微软,上面也都提到了。

1、演示输出各种形式的参数表达式

首先就给我来了个下马威,我用 VS2022 打开之前的解决方案总是有各种问题:项目都被卸载了,也重新加载不了;点击重新加载具有依赖项的项目也不行;点击安装缺少的功能,提示已安装,点击启动就会又启动一个 VS2022,打开解决方案还是这样;感觉就是有 Bug。

然后用 VS2019 进行开发,代码都写完了,运行也没有报错,但是没有效果:

当然,这可能不能怪 VS2019,因为公众号文章开头是这样说的:

我们很高兴地宣布 C# 10 作为 .NET 6 和 Visual Studio 2022 的一部分已经发布了。

就是说应该是需要满足 .NET 6 和 VS2022 这两个条件的。然后既然 Visual Studio 2022 不争气,那么我们来试试 Rider:

果然成功了!jetbrains NB!

2、参数不符合条件时抛出异常

帮助方法如下:

代码语言:javascript
复制
using System;
using System.Runtime.CompilerServices;

namespace WPFPractice.Utils
{
    public class MethodHelper
    {
        /// <summary>
        /// 验证参数(不符合条件则抛出异常)
        /// </summary>
        /// <param name="parameterName"> 参数名 </param>
        /// <param name="condition"> 条件结果(调用时传条件表达式)</param>
        /// <param name="message"> 消息(无需填写,通过调用方参数表达式功能自动获取条件参数的输入表达式)</param>
        public static void ValidateArgument(string parameterName, bool condition,
            [CallerArgumentExpression("condition")] string? message = null)
        {
            if (!condition)
            {
                throw new ArgumentException($"Argument failed validation: <{message}>", parameterName);
            }
        }
    }
}

当然,如果只是为了判断参数是否为 null,且为 null 时抛出异常,微软公众号文章中提到了一个现成的方法:

代码语言:javascript
复制
void MyMethod(object value)
{
    ArgumentNullException.ThrowIfNull(value);
}

反编译后可以看到是微软库 Microsoft.NETCore.App6.0.2System.Private.CoreLib.dll 中的功能,也是用到了 “调用方参数表达式”:

3、获取调用扩展方法的表达式

因为扩展方法也可以当做静态方法来使用( var sequence = ExtensionTester.GetNewSequence (Enumerable.Range (0, 10), 100); ),所以也就很好理解了。另外,微软的例子中没有我后面加的那句 ToList () 的操作,我试了是不行的,因为 Linq 的延迟执行的特性(要实际用到才会执行),如果没有那句,本例的扩展方法不会被执行。

四、结语

就像开头讲述的那样,实际上我昨天看到这个功能时还是挺激动的,虽然只是个不起眼的小功能,但是那种感觉就像是:一件尘封多年的悬案,因为时代的局限,基本被视作无法找到真相了,突然有一天,由于科技的进步(比如指纹技术或者 DNA 检测技术),终于真相大白。

好了,有点晚了,本文明天再发布,明天是情人节,祝我好运吧,也不知道我这个人生的 “悬案” 什么时候能告破。

最后给出源码地址:https://gitee.com/dlgcy/DLGCY_WPFPractice/tree/Blog20220213

感谢阅读。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-02-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 独立观察员博客 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • C#10 新特性 [调用方参数表达式] 解决了我七年前的困惑
    • 一、问题
      • 二、转机
        • 三、实践
          • 1、演示输出各种形式的参数表达式
          • 2、参数不符合条件时抛出异常
          • 3、获取调用扩展方法的表达式
        • 四、结语
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档