1. C# 10 新特性 CallerArgumentExpression

        共 4401字,需瀏覽 9分鐘

         ·

        2021-12-10 10:38

        Intro


        C# 10 支持使用 CallerArgumentExpression 來自動(dòng)地獲取調(diào)用方的信息,這可以簡(jiǎn)化我們現(xiàn)在的一些代碼,讓代碼更加簡(jiǎn)潔,一起看下面的示例吧


        Caller Info


        C# 在 5.0 的時(shí)候開始支持 Caller Info 自動(dòng)獲取調(diào)用方的一些信息,C# 5 開始支持的 Caller Info Attribute 有三個(gè),

        • [CallerMemberName] - 調(diào)用方成員名稱,方法名或者屬性名.
        • [CallerFilePath] - 調(diào)用方源代碼所在文件路徑
        • [CallerLineNumber] - 調(diào)用方所在源代碼的行數(shù)信息

        在方法參數(shù)中添加一個(gè) Attribute 來獲取調(diào)用方信息,使用示例如下:

        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}
        "
        );
        }

        針對(duì) CallerLineNumber 的類型是 int,所以參數(shù)類型需要能夠直接接收 int,如上面的 [CallerLineNumber] int? callerLineNumber = null 也可以改成 [CallerLineNumber] int callerLineNumber = -1 或者 [CallerLineNumber] long callerLineNumber = -1但是不能改成 [CallerLineNumber] string callerLineNumber = null 或者 [CallerLineNumber] short callerLineNumber = -1``string 類型不兼容,short 不能隱式轉(zhuǎn)換上面代碼輸出結(jié)果類似下面:

        Caller?info:
        CallerFilePath:?C:\projects\sources\SamplesInPractice\CSharp10Sample\CallerInfo.cs
        CallerLineNumber:?8
        CallerMemberName:?MainTest

        CallerArgumentExpression

        CallerArgumentExpression 也是屬于一種 Caller Info下面這里是利用 CallerArgumentExpression 實(shí)現(xiàn)的幾個(gè)驗(yàn)證方法,如果參數(shù)不合法就拋出一個(gè)異常,通過 CallerArgumenExpression 來自動(dòng)的獲取調(diào)用方的參數(shù)表達(dá)式

        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?????????{
        ????????????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??argument,?[CallerArgumentExpression("argument")]?string??argumentExpression?=?null)
        ????????where?T?:?class
        ????{
        ????????ArgumentNullException.ThrowIfNull(argument,?argumentExpression);
        ????}
        }

        來看一個(gè)使用調(diào)用示例:

        var?name?=?string.Empty;
        InvokeHelper.TryInvoke(()?=>?Verify.NotNullOrEmpty(name));

        上面的 InvokeHelper.TryInvoke 是封裝的一個(gè)方法,如果有異常會(huì)記錄一個(gè)日志

        上面代碼執(zhí)行結(jié)果如下:

        可以看到我們的名稱也是被記錄了下來 Parameter 名字就是我們傳入的變量名,不需要我們?cè)偈謩?dòng)的額外加一個(gè) nameof(name) 了再來看一個(gè)調(diào)用示例,調(diào)用代碼如下:

        var?num?=?10;
        InvokeHelper.TryInvoke(()?=>?Verify.InRange(num,?2,?5));
        InvokeHelper.TryInvoke(()?=>?Verify.InRange(num,?10?+?2,?10?+?5));

        輸出結(jié)果如下:

        如果沒有變量名或者屬性名等,就會(huì)直接用傳入進(jìn)來的 value 字面量,如果傳入進(jìn)來的是一個(gè)表達(dá)式,那么記錄下來的就是表達(dá)式本身,比如上面輸出的 5/10 + 2,而 num 是傳入的一個(gè)變量,就會(huì)獲取到變量的名字,是不是很神奇,很多驗(yàn)證的地方就可以簡(jiǎn)化很多了

        Sample

        CallerArgumentExpression 有一個(gè)很典型的一個(gè)實(shí)際應(yīng)用就是 .NET 6 里新增的一個(gè) APIArgumentNullException.ThrowIfNull() 方法,這個(gè)方法的實(shí)現(xiàn)如下:

        ///?Throws?an??if??is?null.
        ///?The?reference?type?argument?to?validate?as?non-null.
        ///?The?name?of?the?parameter?with?which??corresponds.
        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我們實(shí)際調(diào)用的時(shí)候就可以不傳參數(shù)名,會(huì)自動(dòng)的獲取參數(shù)名,示例如下:

        object??xiaoMing?=?null;
        InvokeHelper.TryInvoke(()?=>?ArgumentNullException.ThrowIfNull(xiaoMing));

        輸出結(jié)果如下:
        從上面的結(jié)果我們可以看到,參數(shù)名已經(jīng)自動(dòng)的解析出來了

        More

        升級(jí) .NET 6 的小伙伴快用這個(gè)改造你的代碼吧,然后就是很多 null 檢查也可以使用新的 ArgumentNullException.ThrowIfNull 去簡(jiǎn)化代碼吧。

        想使用上述代碼測(cè)試,可以從Github 獲取 https://github.com/WeihanLi/SamplesInPractice/blob/master/CSharp10Sample/CallerInfo.cs


        瀏覽 81
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
          
          

            1. 凉森玲梦一区二区三区av免费 | 毛片一区二区 | h肉动漫在线无修无遮挡 | 中文字幕第一区 | 动漫大胸老师美女黄漫 |