<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          C# 10 新特性 CallerArgumentExpression

          共 4401字,需瀏覽 9分鐘

           ·

          2021-12-10 10:38

          Intro


          C# 10 支持使用 CallerArgumentExpression 來自動(dòng)地獲取調(diào)用方的信息,這可以簡化我們現(xià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}
          "
          );
          }

          針對 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è)方法,如果有異常會記錄一個(gè)日志

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

          可以看到我們的名稱也是被記錄了下來 Parameter 名字就是我們傳入的變量名,不需要我們再手動(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é)果如下:

          如果沒有變量名或者屬性名等,就會直接用傳入進(jìn)來的 value 字面量,如果傳入進(jìn)來的是一個(gè)表達(dá)式,那么記錄下來的就是表達(dá)式本身,比如上面輸出的 5/10 + 2,而 num 是傳入的一個(gè)變量,就會獲取到變量的名字,是不是很神奇,很多驗(yà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ù)名,會自動(dòng)的獲取參數(shù)名,示例如下:

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

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

          More

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

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


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

          手機(jī)掃一掃分享

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

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  强开小嫩苞毛片一二三区 | 亚洲性爱视频 | 人人看,人人摸,人人操 | 成人网站在线免费观看视频 | 操逼逼网址 |