C# 10 新特性 —— CallerArgumentExpression
C# 10 新特性 —— CallerArgumentExpression
Intro
C# 10 支持使用 CallerArgumentExpression
来自动地获取调用方的信息,这可以简化我们现在的一些代码,让代码更加简洁,一起看下面的示例吧
Caller Info
C# 在 5.0 的时候开始支持 Caller Info 自动获取调用方的一些信息,C# 5 开始支持的 Caller Info Attribute 有三个,
[
CallerMemberName
] - 调用方成员名称,方法名或者属性名.[
CallerFilePath
] - 调用方源代码所在文件路径[
CallerLineNumber
] - 调用方所在源代码的行数信息
在方法参数中添加一个 Attribute 来获取调用方信息,使用示例如下:
public static void MainTest()
{// 我是谁,我在哪儿DumpCallerInfo();
}private static void DumpCallerInfo([CallerFilePath] string? callerFilePath = null,[CallerLineNumber] int? callerLineNumber = null,[CallerMemberName] string? callerMemberName = null
)
{Console.WriteLine("Caller info:");Console.WriteLine($@"CallerFilePath: {callerFilePath}
CallerLineNumber: {callerLineNumber}
CallerMemberName: {callerMemberName}
");
}
针对 CallerLineNumber
的类型是 int
,所以参数类型需要能够直接接收 int
,如上面的 [CallerLineNumber] int? callerLineNumber = null
也可以改成 [CallerLineNumber] int callerLineNumber = -1
或者 [CallerLineNumber] long callerLineNumber = -1
但是不能改成 [CallerLineNumber] string callerLineNumber = null
或者 [CallerLineNumber] short callerLineNumber = -1
string
类型不兼容,short 不能隐式转换
上面代码输出结果类似下面:
Caller info:
CallerFilePath: C:\projects\sources\SamplesInPractice\CSharp10Sample\CallerInfo.cs
CallerLineNumber: 8
CallerMemberName: MainTest
CallerArgumentExpression
CallerArgumentExpression
也是属于一种 Caller Info
下面这里是利用 CallerArgumentExpression
实现的几个验证方法,如果参数不合法就抛出一个异常,通过 CallerArgumenExpression
来自动的获取调用方的参数表达式
public static class Verify
{public static void Argument(bool condition, string message, [CallerArgumentExpression("condition")] string? conditionExpression = null){if (!condition) throw new ArgumentException(message: message, paramName: conditionExpression);}public static void NotNullOrEmpty(string argument, [CallerArgumentExpression("argument")] string? argumentExpression = null){if (string.IsNullOrEmpty(argument)){throw new ArgumentException("Can not be null or empty", argumentExpression);}}public static void InRange(int argument, int low, int high,[CallerArgumentExpression("argument")] string? argumentExpression = null,[CallerArgumentExpression("low")] string? lowExpression = null,[CallerArgumentExpression("high")] string? highExpression = null){if (argument < low){throw new ArgumentOutOfRangeException(paramName: argumentExpression,message: $"{argumentExpression} ({argument}) cannot be less than {lowExpression} ({low}).");}if (argument > high){throw new ArgumentOutOfRangeException(paramName: argumentExpression,message: $"{argumentExpression} ({argument}) cannot be greater than {highExpression} ({high}).");}}public static void NotNull<T>(T? argument, [CallerArgumentExpression("argument")] string? argumentExpression = null)where T : class{ArgumentNullException.ThrowIfNull(argument, argumentExpression);}
}
来看一个使用调用示例:
var name = string.Empty;
InvokeHelper.TryInvoke(() => Verify.NotNullOrEmpty(name));
上面的
InvokeHelper.TryInvoke
是封装的一个方法,如果有异常会记录一个日志
上面代码执行结果如下:
可以看到我们的名称也是被记录了下来 Parameter 名字就是我们传入的变量名,不需要我们再手动的额外加一个 nameof(name)
了
再来看一个调用示例,调用代码如下:
var num = 10;
InvokeHelper.TryInvoke(() => Verify.InRange(num, 2, 5));
InvokeHelper.TryInvoke(() => Verify.InRange(num, 10 + 2, 10 + 5));
输出结果如下:
如果没有变量名或者属性名等,就会直接用传入进来的 value 字面量,如果传入进来的是一个表达式,那么记录下来的就是表达式本身,比如上面输出的 5
/10 + 2
,而 num
是传入的一个变量,就会获取到变量的名字,是不是很神奇,很多验证的地方就可以简化很多了
Sample
CallerArgumentExpression
有一个很典型的一个实际应用就是 .NET 6 里新增的一个 API
ArgumentNullException.ThrowIfNull()
方法,这个方法的实现如下:
/// <summary>Throws an <see cref="ArgumentNullException"/> if <paramref name="argument"/> is null.</summary>
/// <param name="argument">The reference type argument to validate as non-null.</param>
/// <param name="paramName">The name of the parameter with which <paramref name="argument"/> corresponds.</param>
public static void ThrowIfNull([NotNull] object? argument, [CallerArgumentExpression("argument")] string? paramName = null)
{if (argument is null){Throw(paramName);}
}[DoesNotReturn]
private static void Throw(string? paramName) =>throw new ArgumentNullException(paramName);
源码可以从 Github 上看 https://github.com/dotnet/runtime/blob/v6.0.0/src/libraries/System.Private.CoreLib/src/System/ArgumentNullException.cs
我们实际调用的时候就可以不传参数名,会自动的获取参数名,示例如下:
object? xiaoMing = null;
InvokeHelper.TryInvoke(() => ArgumentNullException.ThrowIfNull(xiaoMing));
输出结果如下:
从上面的结果我们可以看到,参数名已经自动的解析出来了
More
升级 .NET 6 的小伙伴快用这个改造你的代码吧,然后就是很多 null 检查也可以使用新的 ArgumentNullException.ThrowIfNull
去简化代码吧~~
想使用上述代码测试,可以从 Github 获取 https://github.com/WeihanLi/SamplesInPractice/blob/master/CSharp10Sample/CallerInfo.cs
References
https://www.codeproject.com/Tips/606379/Caller-Info-Attributes-in-Csharp-5-0
https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-10.0/caller-argument-expression?WT.mc_id=DT-MVP-5004222
https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/caller-information?WT.mc_id=DT-MVP-5004222
https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-10?WT.mc_id=DT-MVP-5004222#callerargumentexpression-attribute-diagnostics
https://github.com/dotnet/runtime/blob/v6.0.0/src/libraries/System.Private.CoreLib/src/System/ArgumentNullException.cs
https://github.com/WeihanLi/SamplesInPractice/blob/master/CSharp10Sample/CallerInfo.cs
C# 10 新特性 —— CallerArgumentExpression相关推荐
- C# 10 新特性 —— 补充篇
C# 10 新特性 -- 补充篇 Intro 前面已经写了几篇文章介绍 C# 10 新特性的文章,还有一些小的更新 Constant interpolated strings 在之前的版本中,如果想要 ...
- C# 10 新特性 —— 插值字符串优化
C# 10 新特性 -- 插值字符串优化 Intro 字符串应该是我们平时使用的最多的一个类型,从 C# 6 开始我们开始支持了插值字符串,使得我们可以更方便的进行字符串的操作,现在很多分析器也推荐我 ...
- C# 10 新特性 —— Lambda 优化
C# 10 新特性 -- Lambda 优化 Intro C# 10 对于 Lambda 做了很多的优化,我们可以在 C# 中更加方便地使用委托和 Lambda 了,下面就来看一些示例 Lambda ...
- C# 10 新特性 —— 命名空间的变化
C# 10 新特性 -- 命名空间的变化 Intro C# 10 针对命名空间做了一些改变,主要是 Global Usings 和 File-scoped Namespace,我们前面分享的示例其实也 ...
- JDK 5 ~ 10 新特性倾情整理
转载自 JDK 5 ~ 10 新特性倾情整理 最近连 JDK11都在准备发布的路上了,大家都整明白了吗?也许现在大部分人还在用6-8,8的新特性都没用熟,9刚出不久,10-11就不用说了. 为了大家对 ...
- JavaScript高级之ECMASript 7、8 、9 、10 新特性
第3章 ECMASript 7 新特性 3.1. Array.prototype.includes Includes 方法用来检测数组中是否包含某个元素,返回布尔类型值 3.2. 指数操作符 在ES7 ...
- Java 10新特性
Java 10新特性 Java 10是其23年历史中最快的java版本.Java因其缓慢的增长和发展而受到批评,但Java 10刚刚破坏了这一概念.Java 10是一个具有许多未来变化的版本,其范围和 ...
- Java 10 新特性概述
Java 10是其23年历史中最快发布的java版本.Java因其缓慢的增长和发展而受到批评,但Java 10刚刚破坏了这个概念.Java 10是一个具有许多未来变化的版本,其范围和影响可能并不明显, ...
- Python3.10新特性初体验
Python3.10新特性初体验 注:图片来源 目录 结构模式匹配 [PEP 635] union类型允许X | Y [PEP 604] 带圆括号的上下文管理器 一.结构模式匹配(新增PEP 635) ...
最新文章
- webpack2--webpack 4.X 快速创建demo
- JDBC的两种sql命令发送器比较【Statement:PreparedStatement】
- linux apache2 伪静态,linux Ubuntu apache2 伪静态设置
- How To Make JMeter Behave More Like A Real Browser
- VMware VSphere 虚拟化云计算学习配置笔记(四)
- 文末送书 | Facebook:易于解释的神经元可能会阻碍神经网络的学习
- Xcode插件管理工具Alcatraz
- Windows-Server下加强系统安全性系列之方案【六】
- 数据科学包15-matplotlib详细介绍
- ELK详解(二十一)——elastalert介绍与安装
- Android MediaPlayer的生命周期
- Meta 开源首个 AI 语音翻译系统,闽南话和英语可以直接语音互译
- G1 Concurrent Refinement Thread 在干啥?
- linux下PNG、JEPG、JPG、Webp图片格式互转
- pycharm 如何配置主题背景色 墨绿色
- 网站系统开发公司分析
- 11、Nepxion Discovery 之全链路界面操作蓝绿灰度发布
- 程序的灵活性与可扩展性
- Jitpack使用指南:maven-publish如虎,jitpack如翼 【安卓Java组件化模块化】【更多gradle技巧】
- 【BiSeNet】《BiSeNet:Bilateral Segmentation Network for Real-time Semantic Segmentation》