0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

C#模式匹配完全指南

新機(jī)器視覺 ? 來源:hez2010 ? 2023-09-13 17:33 ? 次閱讀

前言 自從 2017 年 C# 7.0 版本開始引入聲明模式和常數(shù)模式匹配開始,到 2022 年的 C# 11 為止,最后一個板塊列表模式和切片模式匹配也已經(jīng)補(bǔ)齊,當(dāng)初計劃的模式匹配內(nèi)容已經(jīng)基本全部完成。 C# 在模式匹配方面下一步計劃則是支持活動模式(active pattern),這一部分將在本文最后進(jìn)行介紹,而在介紹未來的模式匹配計劃之前,本文主題是對截止 C# 11 模式匹配的~~(不)~~完全指南,希望能對各位開發(fā)者們提升代碼編寫效率、可讀性和質(zhì)量有所幫助。 模式匹配 要使用模式匹配,首先要了解什么是模式。在使用正則表達(dá)式匹配字符串時,正則表達(dá)式自己就是一個模式,而對字符串使用這段正則表達(dá)式進(jìn)行匹配的過程就是模式匹配。而在代碼中也是同樣的,我們對對象采用某種模式進(jìn)行匹配的過程就是模式匹配。

C# 11 支持的模式有很多,包含:

  • 聲明模式(declaration pattern)
  • 類型模式(type pattern)
  • 常數(shù)模式(constant pattern)
  • 關(guān)系模式(relational pattern)
  • 邏輯模式(logical pattern)
  • 屬性模式(property pattern)
  • 位置模式(positional pattern)
  • var 模式(var pattern)
  • 丟棄模式(discard pattern)
  • 列表模式(list pattern)
  • 切片模式(slice pattern)

而其中,不少模式都支持遞歸,也就意味著可以模式嵌套模式,以此來實現(xiàn)更加強(qiáng)大的匹配功能。

模式匹配可以通過switch表達(dá)式來使用,也可以在普通的switch語句中作為case使用,還可以在if條件中通過is來使用。本文主要在switch表達(dá)式中使用模式匹配。

那么接下來就對這些模式進(jìn)行介紹。

實例:表達(dá)式計算器

為了更直觀地介紹模式匹配,我們接下來利用模式匹配來編寫一個表達(dá)式計算器。

為了編寫表達(dá)式計算器,首先我們需要對表達(dá)式進(jìn)行抽象:

publicabstractpartialclassExpr<T>whereT:IBinaryNumber<T>
{
publicabstractTEval(params(stringName,TValue)[]args);
}

我們用上面這個Expr來表示一個表達(dá)式,其中T是操作數(shù)的類型,然后進(jìn)一步將表達(dá)式分為常數(shù)表達(dá)式ConstantExpr、參數(shù)表達(dá)式ParameterExpr、一元表達(dá)式UnaryExpr、二元表達(dá)式BinaryExpr和三元表達(dá)式TernaryExpr。最后提供一個Eval方法,用來計算表達(dá)式的值,該方法可以傳入一個args來提供表達(dá)式計算所需要的參數(shù)。

有了一、二元表達(dá)式自然也需要運(yùn)算符,例如加減乘除等,我們也同時定義Operator來表示運(yùn)算符:

publicabstractrecordOperator
{
publicrecordUnaryOperator(OperatorsOperator):Operator;
publicrecordBinaryOperator(BinaryOperatorsOperator):Operator;
}

然后設(shè)置允許的運(yùn)算符,其中前三個是一元運(yùn)算符,后面的是二元運(yùn)算符:

publicenumOperators
{
[Description("~")]Inv,[Description("-")]Min,[Description("!")]LogicalNot,
[Description("+")]Add,[Description("-")]Sub,[Description("*")]Mul,[Description("/")]Div,
[Description("&")]And,[Description("|")]Or,[Description("^")]Xor,
[Description("==")]Eq,[Description("!=")]Ne,
[Description(">")]Gt,[Description("<")]Lt,[Description(">=")]Ge,[Description("<=")]Le,
[Description("&&")]LogicalAnd,[Description("||")]LogicalOr,
}

你可以能會好奇對T的運(yùn)算能如何實現(xiàn)邏輯與或非,關(guān)于這一點(diǎn),我們直接使用0來代表false,非0代表true。

接下來就是分別實現(xiàn)各類表達(dá)式的時間!

常數(shù)表達(dá)式

常數(shù)表達(dá)式很簡單,它保存一個常數(shù)值,因此只需要在構(gòu)造方法中將用戶提供的值存儲下來。它的Eval實現(xiàn)也只需要簡單返回存儲的值即可:

publicabstractpartialclassExpr<T>whereT:IBinaryNumber<T>
{
publicclassConstantExpr:Expr<T>
{
publicConstantExpr(Tvalue)=>Value=value;

publicTValue{get;}
publicvoidDeconstruct(outTvalue)=>value=Value;

publicoverrideTEval(params(stringName,TValue)[]args)=>Value;
}
}

參數(shù)表達(dá)式

參數(shù)表達(dá)式用來定義表達(dá)式計算過程中的參數(shù),允許用戶在對表達(dá)式執(zhí)行Eval計算結(jié)果的時候傳參,因此只需要存儲參數(shù)名。它的Eval實現(xiàn)需要根據(jù)參數(shù)名在args中找出對應(yīng)的參數(shù)值:

publicabstractpartialclassExpr<T>whereT:IBinaryNumber<T>
{
publicclassParameterExpr:Expr<T>
{
publicParameterExpr(stringname)=>Name=name;

publicstringName{get;}
publicvoidDeconstruct(outstringname)=>name=Name;

//對args進(jìn)行模式匹配
publicoverrideTEval(params(stringName,TValue)[]args)=>argsswitch
{
//如果args有至少一個元素,那我們把第一個元素拿出來存為(name,value),
//然后判斷 name 是否和本參數(shù)表達(dá)式中存儲的參數(shù)名 Name 相同。
//如果相同則返回 value,否則用 args 除去第一個元素剩下的參數(shù)繼續(xù)匹配。
[var(name,value),..vartail]=>name==Name?value:Eval(tail),
//如果args是空列表,則說明在args中沒有找到名字和Name相同的參數(shù),拋出異常
[]=>thrownewInvalidOperationException($"Expectedanargumentnamed{Name}.")
};
}
}

模式匹配會從上往下依次進(jìn)行匹配,直到匹配成功為止。

上面的代碼中你可能會好奇[var (name, value), .. var tail]是個什么模式,這個模式整體看是列表模式,并且列表模式內(nèi)組合使用聲明模式、位置模式和切片模式。例如:

  • []:匹配一個空列表。
  • [1, _, 3]:匹配一個長度是 3,并且首尾元素分別是 1、3 的列表。其中_是丟棄模式,表示任意元素。
  • [_, .., 3]:匹配一個末元素是 3,并且 3 不是首元素的列表。其中..是切片模式,表示任意切片。
  • [1, ..var tail]:匹配一個首元素是 1 的列表,并且將除了首元素之外元素的切片賦值給tail。其中var tailvar模式,用于將匹配結(jié)果賦值給變量。
  • [var head, ..var tail]:匹配一個列表,將它第一個元素賦值給head,剩下元素的切片賦值給tail,這個切片里可以沒有元素。
  • [var (name, value), ..var tail]:匹配一個列表,將它第一個元素賦值給(name, value),剩下元素的切片賦值給tail,這個切片里可以沒有元素。其中(name, value)是位置模式,用于將第一個元素的解構(gòu)結(jié)果根據(jù)位置分別賦值給namevalue,也可以寫成(var name, var value)。

一元表達(dá)式

一元表達(dá)式用來處理只有一個操作數(shù)的計算,例如非、取反等。

publicabstractpartialclassExpr<T>whereT:IBinaryNumber<T>
{
publicclassUnaryExpr:Expr<T>
{
publicUnaryExpr(UnaryOperatorop,Exprexpr)=>(Op,Expr)=(op,expr);

publicUnaryOperatorOp{get;}
publicExprExpr{get;}
publicvoidDeconstruct(outUnaryOperatorop,outExprexpr)=>(op,expr)=(Op,Expr);

//對Op進(jìn)行模式匹配
publicoverrideTEval(params(stringName,TValue)[]args)=>Opswitch
{
//如果Op是UnaryOperator,則將其解構(gòu)結(jié)果賦值給op,然后對op進(jìn)行匹配,op是一個枚舉,而.NET中的枚舉值都是整數(shù)
UnaryOperator(varop)=>opswitch
{
//如果op是Operators.Inv
Operators.Inv=>~Expr.Eval(args),
//如果op是Operators.Min
Operators.Min=>-Expr.Eval(args),
//如果op是Operators.LogicalNot
Operators.LogicalNot=>Expr.Eval(args)==T.Zero?T.One:T.Zero,
//如果op的值大于LogicalNot或者小于0,表示不是一元運(yùn)算符
>Operators.LogicalNotor0=>thrownewInvalidOperationException($"Expectedanunaryoperator,butgot{op}.")
},
//如果Op不是UnaryOperator
_=>thrownewInvalidOperationException("Expectedanunaryoperator.")
};
}
}

上面的代碼中,首先利用了 C# 元組可作為左值的特性,分別使用一行代碼就做完了構(gòu)造方法和解構(gòu)方法的賦值:(Op, Expr) = (op, expr)(op, expr) = (Op, Expr)。如果你好奇能否利用這個特性交換多個變量,答案是可以!

Eval中,首先將類型模式、位置模式和聲明模式組合成UnaryOperator(var op),表示匹配UnaryOperator類型、并且能解構(gòu)出一個元素的東西,如果匹配則將解構(gòu)出來的那個元素賦值給op

然后我們接著對解構(gòu)出來的op進(jìn)行匹配,這里用到了常數(shù)模式,例如Operators.Inv用來匹配op是否是Operators.Inv。常數(shù)模式可以使用各種常數(shù)對對象進(jìn)行匹配。

這里的> Operators.LogicalNot< 0則是關(guān)系模式,分別用于匹配大于Operators.LogicalNot的值和小于0的指。然后利用邏輯模式or將兩個模式組合起來表示或的關(guān)系。邏輯模式除了or之外還有andnot。

由于我們在上面窮舉了枚舉中所有的一元運(yùn)算符,因此也可以將> Operators.LogicalNot or < 0換成丟棄模式_或者 var 模式var foo,兩者都用來匹配任意的東西,只不過前者匹配到后直接丟棄,而后者聲明了個變量foo將匹配到的值放到里面:

opswitch
{
//...
_=>thrownewInvalidOperationException($"Expectedanunaryoperator,butgot{op}.")
}

opswitch
{
//...
varfoo=>thrownewInvalidOperationException($"Expectedanunaryoperator,butgot{foo}.")
}

二元表達(dá)式

二元表達(dá)式用來表示操作數(shù)有兩個的表達(dá)式。有了一元表達(dá)式的編寫經(jīng)驗,二元表達(dá)式如法炮制即可。

publicabstractpartialclassExpr<T>whereT:IBinaryNumber<T>
{
publicclassBinaryExpr:Expr<T>
{
publicBinaryExpr(BinaryOperatorop,Exprleft,Exprright)=>(Op,Left,Right)=(op,left,right);

publicBinaryOperatorOp{get;}
publicExprLeft{get;}
publicExprRight{get;}
publicvoidDeconstruct(outBinaryOperatorop,outExprleft,outExprright)=>(op,left,right)=(Op,Left,Right);

publicoverrideTEval(params(stringName,TValue)[]args)=>Opswitch
{
BinaryOperator(varop)=>opswitch
{
Operators.Add=>Left.Eval(args)+Right.Eval(args),
Operators.Sub=>Left.Eval(args)-Right.Eval(args),
Operators.Mul=>Left.Eval(args)*Right.Eval(args),
Operators.Div=>Left.Eval(args)/Right.Eval(args),
Operators.And=>Left.Eval(args)&Right.Eval(args),
Operators.Or=>Left.Eval(args)|Right.Eval(args),
Operators.Xor=>Left.Eval(args)^Right.Eval(args),
Operators.Eq=>Left.Eval(args)==Right.Eval(args)?T.One:T.Zero,
Operators.Ne=>Left.Eval(args)!=Right.Eval(args)?T.One:T.Zero,
Operators.Gt=>Left.Eval(args)>Right.Eval(args)?T.One:T.Zero,
Operators.Lt=>Left.Eval(args)Left.Eval(args)>=Right.Eval(args)?T.One:T.Zero,
Operators.Le=>Left.Eval(args)<=?Right.Eval(args)???T.One?:?T.Zero,
????????????????Operators.LogicalAnd?=>Left.Eval(args)==T.Zero||Right.Eval(args)==T.Zero?T.Zero:T.One,
Operators.LogicalOr=>Left.Eval(args)==T.Zero&&Right.Eval(args)==T.Zero?T.Zero:T.One,
Operators.LogicalOr=>thrownewInvalidOperationException($"Unexpectedabinaryoperator,butgot{op}.")
},
_=>thrownewInvalidOperationException("Unexpectedabinaryoperator.")
};
}
}

同理,也可以將< Operators.Add or > Operators.LogicalOr換成丟棄模式或者 var 模式。

三元表達(dá)式

三元表達(dá)式包含三個操作數(shù):條件表達(dá)式Cond、為真的表達(dá)式Left、為假的表達(dá)式Right。該表達(dá)式中會根據(jù)Cond是否為真來選擇取Left還是Right,實現(xiàn)起來較為簡單:

publicabstractpartialclassExpr<T>whereT:IBinaryNumber<T>
{
publicclassTernaryExpr:Expr<T>
{
publicTernaryExpr(Exprcond,Exprleft,Exprright)=>(Cond,Left,Right)=(cond,left,right);

publicExprCond{get;}
publicExprLeft{get;}
publicExprRight{get;}
publicvoidDeconstruct(outExprcond,outExprleft,outExprright)=>(cond,left,right)=(Cond,Left,Right);

publicoverrideTEval(params(stringName,TValue)[]args)=>Cond.Eval(args)==T.Zero?Right.Eval(args):Left.Eval(args);
}
}

完成。我們用了僅僅幾十行代碼就完成了全部的核心邏輯!這便是模式匹配的強(qiáng)大之處:簡潔、直觀且高效。

表達(dá)式判等

至此為止,我們已經(jīng)完成了所有的表達(dá)式構(gòu)造、解構(gòu)和計算的實現(xiàn)。接下來我們?yōu)槊恳粋€表達(dá)式實現(xiàn)判等邏輯,即判斷兩個表達(dá)式(字面上)是否相同。

例如a == b ? 2 : 4a == b ? 2 : 5不相同,a == b ? 2 : 4c == d ? 2 : 4不相同,而a == b ? 2 : 4a == b ? 2 : 4相同。

為了實現(xiàn)該功能,我們重寫每一個表達(dá)式的EqualsGetHashCode方法。

常數(shù)表達(dá)式

常數(shù)表達(dá)式判等只需要判斷常數(shù)值是否相等即可:

publicoverrideboolEquals(object?obj)=>objisConstantExpr(varvalue)&&value==Value;
publicoverrideintGetHashCode()=>Value.GetHashCode();

參數(shù)表達(dá)式

參數(shù)表達(dá)式判等只需要判斷參數(shù)名是否相等即可:

publicoverrideboolEquals(object?obj)=>objisParameterExpr(varname)&&name==Name;
publicoverrideintGetHashCode()=>Name.GetHashCode();

一元表達(dá)式

一元表達(dá)式判等,需要判斷被比較的表達(dá)式是否是一元表達(dá)式,如果也是的話則判斷運(yùn)算符和操作數(shù)是否相等:

publicoverrideboolEquals(object?obj)=>objisUnaryExpr({Operator:varop},varexpr)&&(op,expr).Equals((Op.Operator,Expr));
publicoverrideintGetHashCode()=>(Op,Expr).GetHashCode();

上面的代碼中用到了屬性模式{ Operator: var op },用來匹配屬性的值,這里直接組合了聲明模式將屬性Operator的值賦值給了expr。另外,C# 中的元組可以組合起來進(jìn)行判等操作,因此不需要寫op.Equals(Op.Operator) && expr.Equals(Expr),而是可以直接寫(op, expr).Equals((Op.Operator, Expr))。

二元表達(dá)式

和一元表達(dá)式差不多,區(qū)別在于這次多了一個操作數(shù):

publicoverrideboolEquals(object?obj)=>objisBinaryExpr({Operator:varop},varleft,varright)&&(op,left,right).Equals((Op.Operator,Left,Right));
publicoverrideintGetHashCode()=>(Op,Left,Right).GetHashCode();

三元表達(dá)式

和二元表達(dá)式差不多,只不過運(yùn)算符Op變成了操作數(shù)Cond

publicoverrideboolEquals(object?obj)=>objisTernaryExpr(varcond,varleft,varright)&&cond.Equals(Cond)&&left.Equals(Left)&&right.Equals(Right);
publicoverrideintGetHashCode()=>(Cond,Left,Right).GetHashCode();

到此為止,我們?yōu)樗械谋磉_(dá)式都實現(xiàn)了判等。

一些工具方法

我們重載一些Expr的運(yùn)算符方便我們使用:

publicstaticExproperator~(Exproperand)=>newUnaryExpr(new(Operators.Inv),operand);
publicstaticExproperator!(Exproperand)=>newUnaryExpr(new(Operators.LogicalNot),operand);
publicstaticExproperator-(Exproperand)=>newUnaryExpr(new(Operators.Min),operand);
publicstaticExproperator+(Exprleft,Exprright)=>newBinaryExpr(new(Operators.Add),left,right);
publicstaticExproperator-(Exprleft,Exprright)=>newBinaryExpr(new(Operators.Sub),left,right);
publicstaticExproperator*(Exprleft,Exprright)=>newBinaryExpr(new(Operators.Mul),left,right);
publicstaticExproperator/(Exprleft,Exprright)=>newBinaryExpr(new(Operators.Div),left,right);
publicstaticExproperator&(Exprleft,Exprright)=>newBinaryExpr(new(Operators.And),left,right);
publicstaticExproperator|(Exprleft,Exprright)=>newBinaryExpr(new(Operators.Or),left,right);
publicstaticExproperator^(Exprleft,Exprright)=>newBinaryExpr(new(Operators.Xor),left,right);
publicstaticExproperator>(Exprleft,Exprright)=>newBinaryExpr(new(Operators.Gt),left,right);
publicstaticExproperator<(Exprleft,Exprright)=>newBinaryExpr(new(Operators.Lt),left,right);
publicstaticExproperator>=(Exprleft,Exprright)=>newBinaryExpr(new(Operators.Ge),left,right);
publicstaticExproperator<=(Exprleft,Exprright)=>newBinaryExpr(new(Operators.Le),left,right);
publicstaticExproperator==(Exprleft,Exprright)=>newBinaryExpr(new(Operators.Eq),left,right);
publicstaticExproperator!=(Exprleft,Exprright)=>newBinaryExpr(new(Operators.Ne),left,right);
publicstaticimplicitoperatorExpr(Tvalue)=>newConstantExpr(value);
publicstaticimplicitoperatorExpr(stringname)=>newParameterExpr(name);
publicstaticimplicitoperatorExpr(boolvalue)=>newConstantExpr(value?T.One:T.Zero);

publicoverrideboolEquals(object?obj)=>base.Equals(obj);
publicoverrideintGetHashCode()=>base.GetHashCode();

由于重載了==!=,編譯器為了保險起見提示我們重寫EqualsGetHashCode,這里實際上并不需要重寫,因此直接調(diào)用base上的方法保持默認(rèn)行為即可。

然后編寫兩個擴(kuò)展方法用來方便構(gòu)造三元表達(dá)式,和從Description中獲取運(yùn)算符的名字:

publicstaticclassExtensions
{
publicstaticExprSwitch(thisExprcond,Exprleft,Exprright)whereT:IBinaryNumber=>newExpr.TernaryExpr(cond,left,right);
publicstaticstring?GetName(thisTop)whereT:Enum=>typeof(T).GetMember(op.ToString()).FirstOrDefault()?.GetCustomAttribute()?.Description;
}

由于有參數(shù)表達(dá)式參與時需要我們提前提供參數(shù)值才能調(diào)用Eval進(jìn)行計算,因此我們寫一個交互式的Eval來在計算過程中遇到參數(shù)表達(dá)式時提示用戶輸入值,起名叫做InteractiveEval

publicTInteractiveEval()
{
varnames=Array.Empty<string>();
returnEval(GetArgs(this,refnames,refnames));
}
privatestaticTGetArg(stringname,refstring[]names)
{
Console.Write($"Parameter{name}:");
string?str;
do{str=Console.ReadLine();}
while(strisnull);
names=names.Append(name).ToArray();
returnT.Parse(str,NumberStyles.Number,null);
}
privatestatic(stringName,TValue)[]GetArgs(Exprexpr,refstring[]assigned,refstring[]filter)=>exprswitch
{
TernaryExpr(varcond,varleft,varright)=>GetArgs(cond,refassigned,refassigned).Concat(GetArgs(left,refassigned,refassigned)).Concat(GetArgs(right,refassigned,refassigned)).ToArray(),
BinaryExpr(_,varleft,varright)=>GetArgs(left,refassigned,refassigned).Concat(GetArgs(right,refassigned,refassigned)).ToArray(),
UnaryExpr(_,varuexpr)=>GetArgs(uexpr,refassigned,refassigned),
ParameterExpr(varname)=>filterswitch
{
[varhead,..]whenhead==name=>Array.Empty<(stringName,TValue)>(),
[_,..vartail]=>GetArgs(expr,refassigned,reftail),
[]=>new[]{(name,GetArg(name,refassigned))}
},
_=>Array.Empty<(stringName,TValue)>()
};

這里在GetArgs方法中,模式[var head, ..]后面跟了一個when head == name,這里的when用來給模式匹配指定額外的條件,僅當(dāng)條件滿足時才匹配成功,因此[var head, ..] when head == name的含義是,匹配至少含有一個元素的列表,并且將頭元素賦值給head,且僅當(dāng)head == name時匹配才算成功。

最后我們再重寫ToString方法方便輸出表達(dá)式,就全部大功告成了。

測試

接下來讓我測試測試我們編寫的表達(dá)式計算器:

Expr<int>a=4;
Expr<int>b=-3;
Expr<int>x="x";
Expr<int>c=!((a+b)*(a-b)>x);
Expr<int>y="y";
Expr<int>z="z";
Expr<int>expr=(c.Switch(y,z)-a>x).Switch(z+a,y/b);
Console.WriteLine(expr);
Console.WriteLine(expr.InteractiveEval());

運(yùn)行后得到輸出:

((((! ((((4) + (-3)) * ((4) - (-3))) > (x))) ? (y) : (z)) - (4)) > (x)) ? ((z) + (4)) : ((y) / (-3))

然后我們給xyz分別設(shè)置成 42、27 和 35,即可得到運(yùn)算結(jié)果:

Parameterx:42
Parametery:27
Parameterz:35
-9

再測測表達(dá)式判等邏輯:

Expr<int>expr1,expr2,expr3;
{
Expr<int>a=4;
Expr<int>b=-3;
Expr<int>x="x";
Expr<int>c=!((a+b)*(a-b)>x);
Expr<int>y="y";
Expr<int>z="z";
expr1=(c.Switch(y,z)-a>x).Switch(z+a,y/b);
}

{
Expr<int>a=4;
Expr<int>b=-3;
Expr<int>x="x";
Expr<int>c=!((a+b)*(a-b)>x);
Expr<int>y="y";
Expr<int>z="z";
expr2=(c.Switch(y,z)-a>x).Switch(z+a,y/b);
}

{
Expr<int>a=4;
Expr<int>b=-3;
Expr<int>x="x";
Expr<int>c=!((a+b)*(a-b)>x);
Expr<int>y="y";
Expr<int>w="w";
expr3=(c.Switch(y,w)-a>x).Switch(w+a,y/b);
}

Console.WriteLine(expr1.Equals(expr2));
Console.WriteLine(expr1.Equals(expr3));

得到輸出:

True
False

活動模式

在未來,C# 將會引入活動模式,該模式允許用戶自定義模式匹配的方法,例如:

staticboolEven(thisTvalue)whereT:IBinaryInteger=>value%2==0;

上述代碼定義了一個T的擴(kuò)展方法Even,用來匹配value是否為偶數(shù),于是我們便可以這么使用:

varx=3;
vary=xswitch
{
Even()=>"even",
_=>"odd"
};

此外,該模式還可以和解構(gòu)模式結(jié)合,允許用戶自定義解構(gòu)行為,例如:

staticboolInt(thisstringvalue,outintresult)=>int.TryParse(value,outresult);

然后使用的時候:

varx="3";
vary=xswitch
{
Int(varresult)=>result,
_=>0
};

即可對x這個字符串進(jìn)行匹配,如果x可以被解析為int,就取解析結(jié)果result,否則取 0。

總結(jié)

模式匹配極大的方便了我們編寫出簡潔且可讀性高的高質(zhì)量代碼,并且會自動幫我們做窮舉檢查,防止我們漏掉情況。此外,使用模式匹配時,編譯器也會幫我們優(yōu)化代碼,減少完成匹配所需要的比較次數(shù),最終減少分支并提升運(yùn)行效率。

本文中的例子為了覆蓋到全部的模式,不一定采用了最優(yōu)的寫法,這一點(diǎn)各位讀者們也請注意。

本文中的表達(dá)式計算器全部代碼可以前往


聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 字符串
    +關(guān)注

    關(guān)注

    1

    文章

    567

    瀏覽量

    20432
  • 代碼
    +關(guān)注

    關(guān)注

    30

    文章

    4694

    瀏覽量

    68078
  • 模式
    +關(guān)注

    關(guān)注

    0

    文章

    65

    瀏覽量

    13357

原文標(biāo)題:C# 模式匹配完全指南

文章出處:【微信號:vision263com,微信公眾號:新機(jī)器視覺】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦

    C#模式匹配入門指南

    自從 2017 年 C# 7.0 版本開始引入聲明模式和常數(shù)模式匹配開始,到 2022 年的 C# 11 為止,最后一個板塊列表
    的頭像 發(fā)表于 09-18 09:36 ?654次閱讀

    C#上位機(jī)顯示不完全

    我用原子的板子和C#上位機(jī)通訊。上位機(jī)顯示不完全。但是用網(wǎng)絡(luò)助手通訊的話,顯示是完全的。所以應(yīng)該是我C#上位機(jī)的問題。大家?guī)兔纯矗鞘裁磫栴}。以下 是代碼CSharpTCP.rar
    發(fā)表于 04-02 23:26

    C#完全手冊

    C#語言概述點(diǎn)NET編程語言C#運(yùn)行環(huán)境編寫第一個程序C#程序設(shè)計基礎(chǔ)數(shù)據(jù)類型變量和和常量......
    發(fā)表于 05-21 22:00 ?144次下載

    C#教程之DisplayRowCount

    C#教程之DisplayRowCount,很好的C#資料,快來學(xué)習(xí)吧。
    發(fā)表于 04-20 09:59 ?8次下載

    C#教程之FileBatchCopy

    C#教程之FileBatchCopy,很好的C#資料,快來學(xué)習(xí)吧。
    發(fā)表于 04-20 09:59 ?12次下載

    C#教程之彈出模式窗口顯示進(jìn)度條

    C#教程之彈出模式窗口顯示進(jìn)度條,很好的C#資料,快來學(xué)習(xí)吧。
    發(fā)表于 04-20 10:49 ?7次下載

    C#教程之組合

    C#教程之組合,很好的C#資料,快來學(xué)習(xí)吧。
    發(fā)表于 04-20 10:50 ?15次下載

    C#教程之LoadFLASH

    C#教程之LoadFLASH,很好的C#資料,快來學(xué)習(xí)吧。
    發(fā)表于 04-20 10:50 ?9次下載

    C#教程之PrintRemitBill

    C#教程之PrintRemitBill,很好的C#資料,快來學(xué)習(xí)吧。
    發(fā)表于 04-20 13:50 ?16次下載

    C#教程之PrintTopFive

    C#教程之PrintTopFive,很好的C#資料,快來學(xué)習(xí)吧。
    發(fā)表于 04-20 13:50 ?5次下載

    C#教程之VPrintt

    C#教程之VPrintt,很好的C#資料,快來學(xué)習(xí)吧。
    發(fā)表于 04-20 14:06 ?10次下載

    C#教程之WordToHtml

    C#教程之WordToHtml,很好的C#資料,快來學(xué)習(xí)吧。
    發(fā)表于 04-20 14:46 ?15次下載

    《Visual C# 2005開發(fā)技術(shù)》C#與.NET Fram

    《Visual C# 2005開發(fā)技術(shù)》C#與.NET Framework簡介
    發(fā)表于 02-07 15:11 ?0次下載

    《Visual C# 2005開發(fā)技術(shù)》C#程序設(shè)計基礎(chǔ)

    《Visual C# 2005開發(fā)技術(shù)》C#程序設(shè)計基礎(chǔ)
    發(fā)表于 02-07 15:11 ?0次下載

    C#上位機(jī)實戰(zhàn)開發(fā)指南

    C#上位機(jī)實戰(zhàn)開發(fā)指南
    發(fā)表于 11-22 19:25 ?0次下載