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

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

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

C#模式匹配入門指南

jt_rfid5 ? 來源:新機(jī)器視覺 ? 作者:新機(jī)器視覺 ? 2023-09-18 09:36 ? 次閱讀

前言
自從 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)

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

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

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

實(shí)例:表達(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)算能如何實(shí)現(xiàn)邏輯與或非,關(guān)于這一點(diǎn),我們直接使用0來代表false,非0代表true

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

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

常數(shù)表達(dá)式很簡單,它保存一個常數(shù)值,因此只需要在構(gòu)造方法中將用戶提供的值存儲下來。它的Eval實(shí)現(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實(shí)現(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)驗(yàn),二元表達(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,實(shí)現(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)和計算的實(shí)現(xiàn)。接下來我們?yōu)槊恳粋€表達(dá)式實(shí)現(xiàn)判等邏輯,即判斷兩個表達(dá)式(字面上)是否相同。

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

為了實(shí)現(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á)式都實(shí)現(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<(Expr?left,?Expr?right)?=>newBinaryExpr(new(Operators.Lt),left,right);
publicstaticExproperator>=(Exprleft,Exprright)=>newBinaryExpr(new(Operators.Ge),left,right);
publicstaticExproperator<=(Expr?left,?Expr?right)?=>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,這里實(shí)際上并不需要重寫,因此直接調(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)各位讀者們也請注意。



來源:新機(jī)器視覺

審核編輯:湯梓紅


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

    關(guān)注

    1

    文章

    532

    瀏覽量

    57925
  • C語言
    +關(guān)注

    關(guān)注

    180

    文章

    7575

    瀏覽量

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

    關(guān)注

    30

    文章

    4670

    瀏覽量

    67764
  • 計算器
    +關(guān)注

    關(guān)注

    16

    文章

    434

    瀏覽量

    37027
  • 模式匹配
    +關(guān)注

    關(guān)注

    0

    文章

    9

    瀏覽量

    5829

原文標(biāo)題:【光電智造】C# 模式匹配完全指南

文章出處:【微信號:今日光電,微信公眾號:今日光電】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦

    C#(csharp)這門語言的優(yōu)勢在哪

    C#入門
    電路設(shè)計
    發(fā)布于 :2022年12月28日 13:19:49

    C#入門到精通實(shí)例大全

    c#入門到精通,一本最流行的教程
    發(fā)表于 06-14 09:18

    ISE,Keil C和ICCAVR快速入門指南

    ISE,Keil C和ICCAVR快速入門指南:ISE6.2I快速入門介紹,Keil C快速入門
    發(fā)表于 11-01 23:20 ?0次下載
    ISE,Keil <b class='flag-5'>C</b>和ICCAVR快速<b class='flag-5'>入門</b><b class='flag-5'>指南</b>

    c#入門經(jīng)典第4版全書pdf

    C#入門經(jīng)典(第4版)》通過C#可以很容易地學(xué)習(xí).NET framework 3.5的強(qiáng)大功能,所以C#是開始您編程生涯的絕佳方式。《C#
    發(fā)表于 10-17 10:31 ?0次下載

    C# 2.0編程入門視頻

    C# 2.0編程入門視頻!資料來源網(wǎng)絡(luò),如有侵權(quán),敬請見諒
    發(fā)表于 11-20 15:13 ?6次下載

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

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

    Visual C# 2010從入門到精通13章源碼

    書:Visual C# 2010從入門到精通各章節(jié)程序源碼
    發(fā)表于 05-10 15:44 ?11次下載

    Visual C# 2010從入門到精通09章源碼

    書:Visual C# 2010從入門到精通各章節(jié)程序源碼
    發(fā)表于 05-10 16:00 ?13次下載

    Visual C# 2010從入門到精通03章源碼

    書:Visual C# 2010從入門到精通各章節(jié)程序源碼
    發(fā)表于 05-10 16:00 ?7次下載

    C#教程—最佳的入門教程

    C#教程—最佳的入門教程
    發(fā)表于 03-01 12:48 ?0次下載

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

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

    慕課嵌入式開發(fā)及應(yīng)用(第二章.C#快速入門與通信編程方法)

    慕課蘇州大學(xué).嵌入式開發(fā)及應(yīng)用.第二章.入門與軟件框架.C#快速入門與通信編程方法0 目錄2 入門與軟件框架2.9 C#快速
    發(fā)表于 11-02 18:35 ?13次下載
    慕課嵌入式開發(fā)及應(yīng)用(第二章.<b class='flag-5'>C#</b>快速<b class='flag-5'>入門</b>與通信編程方法)

    Renesas R32C/118 入門套件快速入門指南

    Renesas R32C/118 入門套件快速入門指南
    發(fā)表于 04-21 19:42 ?0次下載
    Renesas R32<b class='flag-5'>C</b>/118 <b class='flag-5'>入門</b>套件快速<b class='flag-5'>入門</b><b class='flag-5'>指南</b>

    Renesas R32C/111 入門套件快速入門指南

    Renesas R32C/111 入門套件快速入門指南
    發(fā)表于 04-26 19:36 ?0次下載
    Renesas R32<b class='flag-5'>C</b>/111 <b class='flag-5'>入門</b>套件快速<b class='flag-5'>入門</b><b class='flag-5'>指南</b>

    C#模式匹配完全指南

    要使用模式匹配,首先要了解什么是模式。在使用正則表達(dá)式匹配字符串時,正則表達(dá)式自己就是一個模式,而對字符串使用這段正則表達(dá)式進(jìn)行
    的頭像 發(fā)表于 09-13 17:33 ?396次閱讀