C# 7 için model eşleştirmePattern Matching for C# 7
C# için model eşleştirme uzantıları, örnek dillerin birçok avantajını ve işlev dillerinin örüntüsünün eşleşmesini, ancak temel alınan dilin hisşiyle sorunsuz bir şekilde tümleşmesini sağlar.Pattern matching extensions for C# enable many of the benefits of algebraic data types and pattern matching from functional languages, but in a way that smoothly integrates with the feel of the underlying language. Temel özellikler şunlardır: anlam anlamı verilerin şekli tarafından tanımlanan türler olan kayıt türleri; ve, bu veri türlerinin son derece daha çok daha fazla düzeyde ayrışmalarını sağlayan yeni bir ifade biçimi olan kalıp eşleme.The basic features are: record types, which are types whose semantic meaning is described by the shape of the data; and pattern matching, which is a new expression form that enables extremely concise multilevel decomposition of these data types. Bu yaklaşımın öğeleri, F # ve Scalaprogramlama dillerinde ilgili özellikler tarafından ilham oluşur.Elements of this approach are inspired by related features in the programming languages F# and Scala.
Is ifadesiIs expression
İşleci, bir is
ifadeyi bir düzene karşı test etmek üzere genişletilir.The is
operator is extended to test an expression against a pattern.
relational_expression
: relational_expression 'is' pattern
;
Bu relational_expression biçimi, C# belirtiminde var olan formlara ek niteliğindedir.This form of relational_expression is in addition to the existing forms in the C# specification. Belirtecin solundaki relational_expression is
bir değer belirlememezse veya bir tür içermiyorsa derleme zamanı hatası oluşur.It is a compile-time error if the relational_expression to the left of the is
token does not designate a value or does not have a type.
Düzenin her tanımlayıcısı , işleçten sonra kesinlikle atanan yeni bir yerel değişken sunar is
true
(yani, doğru olduğunda, kesin olarak atanır).Every identifier of the pattern introduces a new local variable that is definitely assigned after the is
operator is true
(i.e. definitely assigned when true).
Note: bir ve constant_pattern türü arasında teknik bir belirsizlik vardır
is-expression
; bunlardan biri, tam bir tanımlayıcının geçerli bir ayrıştırmasından kaynaklanabilir.Note: There is technically an ambiguity between type in anis-expression
and constant_pattern, either of which might be a valid parse of a qualified identifier. Bunu, dilin önceki sürümleriyle uyumluluk için bir tür olarak bağlamaya çalışırız; yalnızca bu başarısız olursa, diğer bağlamlarda yaptığımız gibi, bulduğu ilk şeyi (sabit veya bir tür olması gerekir) çözeceğiz.We try to bind it as a type for compatibility with previous versions of the language; only if that fails do we resolve it as we do in other contexts, to the first thing found (which must be either a constant or a type). Bu belirsizlik yalnızca bir ifadenin sağ tarafında bulunuris
.This ambiguity is only present on the right-hand-side of anis
expression.
DesenlerPatterns
Desenler, is
işleç içinde ve bir switch_statement , gelen verilerin karşılaştırılacağı verilerin şeklini ifade etmek için kullanılır.Patterns are used in the is
operator and in a switch_statement to express the shape of data against which incoming data is to be compared. Desenler, verilerin bölümlerinin alt desenlerle eşleştirileceği şekilde özyinelemeli olabilir.Patterns may be recursive so that parts of the data may be matched against sub-patterns.
pattern
: declaration_pattern
| constant_pattern
| var_pattern
;
declaration_pattern
: type simple_designation
;
constant_pattern
: shift_expression
;
var_pattern
: 'var' simple_designation
;
Note: bir ve constant_pattern türü arasında teknik bir belirsizlik vardır
is-expression
; bunlardan biri, tam bir tanımlayıcının geçerli bir ayrıştırmasından kaynaklanabilir.Note: There is technically an ambiguity between type in anis-expression
and constant_pattern, either of which might be a valid parse of a qualified identifier. Bunu, dilin önceki sürümleriyle uyumluluk için bir tür olarak bağlamaya çalışırız; yalnızca bu başarısız olursa, diğer bağlamlarda yaptığımız gibi, bulduğu ilk şeyi (sabit veya bir tür olması gerekir) çözeceğiz.We try to bind it as a type for compatibility with previous versions of the language; only if that fails do we resolve it as we do in other contexts, to the first thing found (which must be either a constant or a type). Bu belirsizlik yalnızca bir ifadenin sağ tarafında bulunuris
.This ambiguity is only present on the right-hand-side of anis
expression.
Bildirim kalıbıDeclaration pattern
Declaration_pattern her ikisi de bir ifadenin verilen türden olduğunu sınar ve test başarılı olursa bu türe yayınlar.The declaration_pattern both tests that an expression is of a given type and casts it to that type if the test succeeds. Simple_designation bir tanımlayıcıse, verilen tanımlayıcı tarafından adlandırılan belirtilen türde yerel bir değişken tanıtır.If the simple_designation is an identifier, it introduces a local variable of the given type named by the given identifier. Bu yerel değişken, bir kalıp eşleme işleminin sonucu true olduğunda kesinlikle atanır .That local variable is definitely assigned when the result of the pattern-matching operation is true.
declaration_pattern
: type simple_designation
;
Bu ifadenin çalışma zamanı anlam düzeyi, sol taraftaki relational_expression işlenenin çalışma zamanı türünü, düzendeki türe göre sınar.The runtime semantic of this expression is that it tests the runtime type of the left-hand relational_expression operand against the type in the pattern. Çalışma zamanı türü (veya bazı alt tür) ise, sonucu is operator
olur true
.If it is of that runtime type (or some subtype), the result of the is operator
is true
. Sonuç olduğunda sol işlenenin değerine atanan tanımlayıcı tarafından adlı yeni bir yerel değişken bildirir true
.It declares a new local variable named by the identifier that is assigned the value of the left-hand operand when the result is true
.
Sol taraftaki statik türdeki belirli birleşimler ve verilen tür uyumsuz olarak değerlendirilir ve derleme zamanı hatası ile sonuçlanır.Certain combinations of static type of the left-hand-side and the given type are considered incompatible and result in compile-time error. Statik türdeki bir değer, E
T
bir kimlik dönüştürmesi, örtük bir başvuru dönüştürmesi, paketleme dönüştürmesi, açık bir başvuru dönüştürmesi veya ' den ' a bir kutudan çıkarma dönüştürmesi varsa, türle uyumlu olarak kabul edilir E
T
.A value of static type E
is said to be pattern compatible with the type T
if there exists an identity conversion, an implicit reference conversion, a boxing conversion, an explicit reference conversion, or an unboxing conversion from E
to T
. Türü bir ifade E
ile eşleştirildiği bir tür deseninin türüyle uyumlu kalıp değilse, derleme zamanı hatasıdır.It is a compile-time error if an expression of type E
is not pattern compatible with the type in a type pattern that it is matched with.
Note: C# 7,1 ' de , giriş türü veya türü açık bir tür ise, bir kalıp eşleme işlemine izin vermek için bunu genişlettik
T
.Note: In C# 7.1 we extend this to permit a pattern-matching operation if either the input type or the typeT
is an open type. Bu paragraf şu şekilde değiştirilmiştir:This paragraph is replaced by the following:Sol taraftaki statik türdeki belirli birleşimler ve verilen tür uyumsuz olarak değerlendirilir ve derleme zamanı hatası ile sonuçlanır.Certain combinations of static type of the left-hand-side and the given type are considered incompatible and result in compile-time error. Statik türdeki bir değer,
E
T
bir kimlik dönüştürmesi, örtük bir başvuru dönüştürmesi, paketleme dönüştürmesi, açık bir başvuru dönüştürmesi ya da yaE
T
da ya da açık bir tür ise, ya da ya daE
T
bir açık tür varsa, türle uyumlu olarak kabul edilir.A value of static typeE
is said to be pattern compatible with the typeT
if there exists an identity conversion, an implicit reference conversion, a boxing conversion, an explicit reference conversion, or an unboxing conversion fromE
toT
, or if eitherE
orT
is an open type. Türü bir ifadeE
ile eşleştirildiği bir tür deseninin türüyle uyumlu kalıp değilse, derleme zamanı hatasıdır.It is a compile-time error if an expression of typeE
is not pattern compatible with the type in a type pattern that it is matched with.
Bildirim stili, başvuru türlerinin çalışma zamanı türü testlerini gerçekleştirmek için yararlıdır ve deyim yerini alırThe declaration pattern is useful for performing run-time type tests of reference types, and replaces the idiom
var v = expr as Type;
if (v != null) { // code using v }
Biraz daha kısaWith the slightly more concise
if (expr is Type v) { // code using v }
Tür null yapılabilir bir değer türünde ise bu bir hatadır.It is an error if type is a nullable value type.
Bildirim stili, null yapılabilir türlerin değerlerini test etmek için kullanılabilir: Nullable<T>
T
T2 id
değer null ve türü ise ya T2
T
da bir temel türü veya arabirimi T
olan bir tür değeri (veya kutulanmış) bir tür düzeniyle eşleşir.The declaration pattern can be used to test values of nullable types: a value of type Nullable<T>
(or a boxed T
) matches a type pattern T2 id
if the value is non-null and the type of T2
is T
, or some base type or interface of T
. Örneğin, kod parçasındaFor example, in the code fragment
int? x = 3;
if (x is int v) { // code using v }
if
Deyimin koşulu true
çalışma zamanında ve değişken, v
3
blok içindeki tür değerini tutar int
.The condition of the if
statement is true
at runtime and the variable v
holds the value 3
of type int
inside the block.
Sabit modelConstant pattern
constant_pattern
: shift_expression
;
Sabit bir model, bir ifadenin değerini sabit bir değere göre sınar.A constant pattern tests the value of an expression against a constant value. Sabit, değişmez değer, belirtilen bir değişkenin adı ya da bir const
numaralandırma sabiti veya bir ifade gibi herhangi bir sabit ifade olabilir typeof
.The constant may be any constant expression, such as a literal, the name of a declared const
variable, or an enumeration constant, or a typeof
expression.
Hem e hem de c integral türtürsiyse, ifadenin sonucu ise, model eşleşir olarak kabul edilir e == c
true
.If both e and c are of integral types, the pattern is considered matched if the result of the expression e == c
is true
.
Aksi takdirde, değer döndürülürse eşleşen olarak object.Equals(e, c)
değerlendirilir true
.Otherwise the pattern is considered matching if object.Equals(e, c)
returns true
. Bu durumda, statik e türü, sabit türü ile uyumlu kalıp değilse, derleme zamanı hatası olur.In this case it is a compile-time error if the static type of e is not pattern compatible with the type of the constant.
Var desenininVar pattern
var_pattern
: 'var' simple_designation
;
E ifadesi her zaman var_pattern eşleşir.An expression e matches a var_pattern always. Diğer bir deyişle, var olan bir model ile eşleşme her zaman başarılı olur.In other words, a match to a var pattern always succeeds. Simple_designation bir tanımlayıcıse, çalışma zamanında e değeri yeni tanıtılan bir yerel değişkene bağlanır.If the simple_designation is an identifier, then at runtime the value of e is bound to a newly introduced local variable. Yerel değişkenin türü, e'nin statik türüdür.The type of the local variable is the static type of e.
Ad var
bir türe bağlandığında bir hatadır.It is an error if the name var
binds to a type.
Switch deyimleriSwitch statement
switch
Deyimi, anahtar ifadesiyle eşleşen ilişkili bir düzene sahip olan ilk bloğun yürütülmesi için seçilecek şekilde genişletilir.The switch
statement is extended to select for execution the first block having an associated pattern that matches the switch expression.
switch_label
: 'case' complex_pattern case_guard? ':'
| 'case' constant_expression case_guard? ':'
| 'default' ':'
;
case_guard
: 'when' expression
;
Desenlerin eşleştirildiği sıra tanımlı değil.The order in which patterns are matched is not defined. Bir derleyicinin desenleri sıralamayla eşleşmesi ve diğer desenlerin eşleşme sonucunu hesaplamak için zaten eşleşen desenlerin sonuçlarını yeniden kullanmak için izin verilir.A compiler is permitted to match patterns out of order, and to reuse the results of already matched patterns to compute the result of matching of other patterns.
Bir durum koruması varsa, ifadesi tür olur bool
.If a case-guard is present, its expression is of type bool
. Bu, büyük/küçük harf karşılanması durumunda karşılanması gereken ek bir koşul olarak değerlendirilir.It is evaluated as an additional condition that must be satisfied for the case to be considered satisfied.
Switch_label çalışma zamanında hiçbir etkisi yoksa, bu bir hatadır çünkü bu, kendi deseninin önceki durumlar tarafından bir alt grup haline getirilir.It is an error if a switch_label can have no effect at runtime because its pattern is subsumed by previous cases. [TODO: derleyicinin bu kararya ulaşmak için kullanması gereken tekniklerin daha kesin olması gerekir.][TODO: We should be more precise about the techniques the compiler is required to use to reach this judgment.]
Bir switch_label olarak belirtilen bir model değişkeni, yalnızca bu durum bloğu tam olarak bir switch_label içeriyorsa, büyük/küçük harf bloğunda kesinlikle atanır.A pattern variable declared in a switch_label is definitely assigned in its case block if and only if that case block contains precisely one switch_label.
[TODO: bir anahtar bloğunun ne zaman ulaşılabilir olduğunu belirtmemiz gerekir.][TODO: We should specify when a switch block is reachable.]
Model değişkenlerinin kapsamıScope of pattern variables
Bir düzende belirtilen değişkenin kapsamı aşağıdaki gibidir:The scope of a variable declared in a pattern is as follows:
- Desenler bir Case etiketse, değişkenin kapsamı Case bloğu olur.If the pattern is a case label, then the scope of the variable is the case block.
Aksi takdirde, değişken bir is_pattern ifadesinde, ve kapsamı, is_pattern ifadesini içeren ifadeyi hemen kapsayan yapıyı temel alır:Otherwise the variable is declared in an is_pattern expression, and its scope is based on the construct immediately enclosing the expression containing the is_pattern expression as follows:
- İfade bir ifade ifadesinde ise, kapsamı lambda gövdesidir.If the expression is in an expression-bodied lambda, its scope is the body of the lambda.
- İfade bir ifade-Bodied yöntemi veya özelliği ise, kapsamı yöntemin veya özelliğin gövdesidir.If the expression is in an expression-bodied method or property, its scope is the body of the method or property.
- İfade, yan tümcesinin bir
when
yan tümcesinde isecatch
, bucatch
yan tümce olur.If the expression is in awhen
clause of acatch
clause, its scope is thatcatch
clause. - İfade bir iteration_statement ise, kapsamı yalnızca o deyimdir.If the expression is in an iteration_statement, its scope is just that statement.
- Aksi takdirde, ifade başka bir deyim formundadır, kapsamı deyimi içeren kapsamdır.Otherwise if the expression is in some other statement form, its scope is the scope containing the statement.
Kapsamı belirlemek amacıyla bir embedded_statement kendi kapsamında olduğu kabul edilir.For the purpose of determining the scope, an embedded_statement is considered to be in its own scope. Örneğin, bir if_statement için dilbilgisiFor example, the grammar for an if_statement is
if_statement
: 'if' '(' boolean_expression ')' embedded_statement
| 'if' '(' boolean_expression ')' embedded_statement 'else' embedded_statement
;
Bu nedenle bir if_statement denetimli bildiriminde bir model değişkeni bildiriliyorsa, kapsamı bu embedded_statement kısıtlıdır:So if the controlled statement of an if_statement declares a pattern variable, its scope is restricted to that embedded_statement:
if (x) M(y is var z);
Bu durumda, öğesinin kapsamı z
Embedded deyimidir M(y is var z);
.In this case the scope of z
is the embedded statement M(y is var z);
.
Diğer nedenlerden dolayı diğer nedenlerle hatalar vardır (örneğin, bir parametrenin varsayılan değeri veya bir özniteliği, her ikisi de bir hata olan bu içerikler sabit bir ifade gerektirdiğinden).Other cases are errors for other reasons (e.g. in a parameter's default value or an attribute, both of which are an error because those contexts require a constant expression).
C# 7,3 ' de, bir model değişkeninin bildirilebilecek aşağıdaki bağlamları ekledik:In C# 7.3 we added the following contexts in which a pattern variable may be declared:
- İfade bir Oluşturucu başlatıcısında ise, kapsamı Oluşturucu başlatıcısı ve oluşturucunun gövdesi olur.If the expression is in a constructor initializer, its scope is the constructor initializer and the constructor's body.
- İfade bir alan başlatıcısında ise, kapsamı göründüğü equals_value_clause .If the expression is in a field initializer, its scope is the equals_value_clause in which it appears.
- İfade bir lambda gövdesine çevrilebilmesi için belirtilen bir sorgu yan tümcesinde ise, kapsamı yalnızca o ifadedir.If the expression is in a query clause that is specified to be translated into the body of a lambda, its scope is just that expression.
Sözdizimsel Kesinleştirme değişiklikleriChanges to syntactic disambiguation
C# dilbilgisinin belirsiz olduğu ve dil belirtiminin bu belirsizlikleri nasıl çözümlendiğini belirten genel türler içeren durumlar vardır:There are situations involving generics where the C# grammar is ambiguous, and the language spec says how to resolve those ambiguities:
7.6.5.2 dilbilgisi belirsizlikleri7.6.5.2 Grammar ambiguities
Basit ad (§ 7.6.3) ve üye erişimi (§ 7.6.5) için üretimler, ifadelerde dilbilgisi için verebilir.The productions for simple-name (§7.6.3) and member-access (§7.6.5) can give rise to ambiguities in the grammar for expressions. Örneğin, ifade:For example, the statement:
F(G<A,B>(7));
iki bağımsız değişkenle bir çağrı olarak yorumlanamıyor
F
G < A
B > (7)
.could be interpreted as a call toF
with two arguments,G < A
andB > (7)
. Alternatif olarak,F
G
iki tür bağımsız değişkeni ve bir normal bağımsız değişken ile genel bir yönteme çağrı olan bir bağımsız değişkenle bir çağrı olarak yorumlanabilecek.Alternatively, it could be interpreted as a call toF
with one argument, which is a call to a generic methodG
with two type arguments and one regular argument.
Bir belirteç dizisi bir basit ad (§ 7.6.3), üye erişimi (§ 7.6.5) veya bir tür bağımsız değişkeni (§ 18.5.2) ile biten işaretçi-üye erişimi (§ 4.4.1) olarak ayrıştırılamıyorsa, kapanış belirtecinin hemen ardından gelen belirteç
>
incelenir.If a sequence of tokens can be parsed (in context) as a simple-name (§7.6.3), member-access (§7.6.5), or pointer-member-access (§18.5.2) ending with a type-argument-list (§4.4.1), the token immediately following the closing>
token is examined. Bunlardan biri iseIf it is one of( ) ] } : ; , . ? == != | ^
daha sonra tür bağımsız değişken listesi , basit ad, üye erişimi veya işaretçi-üye erişiminin bir parçası olarak korunur ve belirteçleri dizisinin diğer olası ayrıştırması atılır.then the type-argument-list is retained as part of the simple-name, member-access or pointer-member-access and any other possible parse of the sequence of tokens is discarded. Aksi takdirde, tür bağımsız değişken listesi , belirteçlerin başka bir olası ayrıştırması olmasa bile, basit ad, üye erişimi veya > işaretçi-üye erişiminin parçası olarak kabul edilmez.Otherwise, the type-argument-list is not considered to be part of the simple-name, member-access or > pointer-member-access, even if there is no other possible parse of the sequence of tokens. Bir ad alanı-veya-tür adı (§ 3,8) içinde bir tür bağımsız değişken listesi ayrıştırılırken bu kuralların uygulanmadığını unutmayın.Note that these rules are not applied when parsing a type-argument-list in a namespace-or-type-name (§3.8). İfadeThe statement
F(G<A,B>(7));
Bu kurala göre,
F
G
iki tür bağımsız değişkeni ve bir normal bağımsız değişken ile genel bir yönteme çağrı olan bir bağımsız değişkenle bir çağrı olarak yorumlanacaktır.will, according to this rule, be interpreted as a call toF
with one argument, which is a call to a generic methodG
with two type arguments and one regular argument. DeyimlerThe statementsF(G < A, B > 7); F(G < A, B >> 7);
, her biri iki bağımsız değişkenle bir çağrı olarak yorumlanır
F
.will each be interpreted as a call toF
with two arguments. İfadeThe statementx = F < A > +y;
, bir
x = (F < A) > (+y)
Type-argument-List ve bir ikili Plus işleci tarafından izlenen basit ad yerine, daha küçüktür işleci, büyüktür operatörü ve birli Plus işleci olarak yorumlanır.will be interpreted as a less than operator, greater than operator, and unary plus operator, as if the statement had been writtenx = (F < A) > (+y)
, instead of as a simple-name with a type-argument-list followed by a binary plus operator. İfadesindeIn the statementx = y is C<T> + z;
belirteçler,
C<T>
tür bağımsız değişkeni-listesi olan bir ad alanı veya-tür adı olarak yorumlanır.the tokensC<T>
are interpreted as a namespace-or-type-name with a type-argument-list.
C# 7 ' de sunulan ve bu Kesinleştirme kurallarını dilin karmaşıklığını işlemeye yetecek kadar yeterli olmayan bir dizi değişiklik vardır.There are a number of changes being introduced in C# 7 that make these disambiguation rules no longer sufficient to handle the complexity of the language.
Out değişken bildirimleriOut variable declarations
Artık bir out bağımsız değişkeninde bir değişken bildirmek mümkündür:It is now possible to declare a variable in an out argument:
M(out Type name);
Ancak, tür genel olabilir:However, the type may be generic:
M(out A<B> name);
Bağımsız değişken için dil dilbilgisi ifadesi kullandığından, bu bağlam Kesinleştirme kuralına tabidir.Since the language grammar for the argument uses expression, this context is subject to the disambiguation rule. Bu durumda, kapanış, >
bir tür bağımsız değişken listesi olarak işlenmesine izin veren belirteçlerden biri olmayan bir tanımlayıcı tarafından izlenir.In this case the closing >
is followed by an identifier, which is not one of the tokens that permits it to be treated as a type-argument-list. Bu nedenle , bir tür bağımsız değişken listesi için belirsizliği tetikleyen belirteç kümesine tanımlayıcı eklemeyi önerin.I therefore propose to add identifier to the set of tokens that triggers the disambiguation to a type-argument-list.
Tanımlama grupları ve ayrıştırma bildirimleriTuples and deconstruction declarations
Bir demet sabit değeri tamamen aynı sorun üzerinde çalışır.A tuple literal runs into exactly the same issue. Tanımlama grubu ifadesini göz önünde bulundurunConsider the tuple expression
(A < B, C > D, E < F, G > H)
Bağımsız değişken listesini ayrıştırmak için eski C# 6 kuralları altında, bu, ilk olarak ile başlayarak dört öğe içeren bir tanımlama grubu olarak ayrıştırılabilir A < B
.Under the old C# 6 rules for parsing an argument list, this would parse as a tuple with four elements, starting with A < B
as the first. Bununla birlikte, bu, bir zaman oluşumunun solunda göründüğünde, yukarıdaki tanımlayıcı belirteç tarafından tetiklenerek, daha önce açıklandığı gibi kesinleştirilmesine istiyoruz:However, when this appears on the left of a deconstruction, we want the disambiguation triggered by the identifier token as described above:
(A<B,C> D, E<F,G> H) = e;
Bu, ilki tür ve adı olan iki değişken bildiren bir deinşaat bildirimidir A<B,C>
D
.This is a deconstruction declaration which declares two variables, the first of which is of type A<B,C>
and named D
. Diğer bir deyişle, demet değişmez değeri her biri bir bildirim ifadesi olan iki ifade içerir.In other words, the tuple literal contains two expressions, each of which is a declaration expression.
Belirtim ve derleyicinin basitliği için, bu demet sabit değerinin göründüğü yerde iki öğeli bir kayıt kümesi olarak ayrıştırılmasını (atamanın sol tarafında görünüp başlatılmayacağını) önerdim.For simplicity of the specification and compiler, I propose that this tuple literal be parsed as a two-element tuple wherever it appears (whether or not it appears on the left-hand-side of an assignment). Bu, önceki bölümde açıklanan belirsizinin doğal bir sonucu olacaktır.That would be a natural result of the disambiguation described in the previous section.
Desenler eşlemePattern-matching
Model eşleştirme, ifade türü belirsizliğin ortaya çıkarmakta olduğu yeni bir bağlam tanıtır.Pattern matching introduces a new context where the expression-type ambiguity arises. Daha önce bir işlecin sağ tarafı is
bir türdür.Previously the right-hand-side of an is
operator was a type. Artık bir tür veya ifade olabilir ve bir tür ise, bir tanımlayıcı gelebilir.Now it can be a type or expression, and if it is a type it may be followed by an identifier. Teknik olarak, var olan kodun anlamını değiştirebilir:This can, technically, change the meaning of existing code:
var x = e is T < A > B;
Bu, C# 6 kuralları altında şu şekilde ayrıştırılabilirThis could be parsed under C#6 rules as
var x = ((e is T) < A) > B;
ancak C# 7 kuralları altında (yukarıda önerilen Kesinleştirme ile birlikte)but under under C#7 rules (with the disambiguation proposed above) would be parsed as
var x = e is T<A> B;
Bu tür bir değişken bildirir B
T<A>
.which declares a variable B
of type T<A>
. Neyse ki, yerel ve Roslyn derleyicileri, C# 6 kodunda sözdizimi hatası vertikleri bir hata içermektedir.Fortunately, the native and Roslyn compilers have a bug whereby they give a syntax error on the C#6 code. Bu nedenle, bu son değişiklik bir sorun değildir.Therefore this particular breaking change is not a concern.
Örüntü eşleme, bir türü seçmek için belirsizlik çözümünü destekleyen ek belirteçler sunar.Pattern-matching introduces additional tokens that should drive the ambiguity resolution toward selecting a type. Mevcut geçerli C# 6 kodunun aşağıdaki örnekleri, ek Kesinleştirme kuralları olmadan bozulur:The following examples of existing valid C#6 code would be broken without additional disambiguation rules:
var x = e is A<B> && f; // &&
var x = e is A<B> || f; // ||
var x = e is A<B> & f; // &
var x = e is A<B>[]; // [
Kesinleştirme kuralında önerilen değişiklikProposed change to the disambiguation rule
Belirteçlerin, ayırt edici belirteç listesini değiştirme belirtiminiI propose to revise the specification to change the list of disambiguating tokens from
( ) ] } : ; , . ? == != | ^
kullanıcısıto
( ) ] } : ; , . ? == != | ^ && || & [
Ve bazı bağlamlarda tanımlayıcıyı Kesinleştirme belirteci olarak değerlendiririz.And, in certain contexts, we treat identifier as a disambiguating token. Bu bağlamlar, ayırt edilen belirteçlerin sırasının, is
case
out
bir demet sabit öğesinin ilk öğesi ayrıştırılırken (Bu durumda, belirteçlerin önünde (
veya :
ondan sonra tanımlayıcı bir ,
) ya da bir dizi sabit değerinin sonraki bir öğesi ayrıştırılırken, ya da ya da bir dizi anahtar kelimeden hemen önce gelir.Those contexts are where the sequence of tokens being disambiguated is immediately preceded by one of the keywords is
, case
, or out
, or arises while parsing the first element of a tuple literal (in which case the tokens are preceded by (
or :
and the identifier is followed by a ,
) or a subsequent element of a tuple literal.
Değişiklik Kesinleştirme kuralıModified disambiguation rule
Düzeltilen Kesinleştirme kuralı şuna benzer olacaktırThe revised disambiguation rule would be something like this
Bir belirteç dizisi bir basit-ad (§ 7.6.3), üye erişimi (§ 7.6.5) veya bir tür bağımsız değişkeni (§ 18.5.2) ile biten işaretçi-üye-erişim (§ 4.4.1) olarak ayrıştırılabiliyorsanız, kapatma belirtecinin hemen ardından gelen belirteç
>
incelenmekte olup olmadığını görmek içinIf a sequence of tokens can be parsed (in context) as a simple-name (§7.6.3), member-access (§7.6.5), or pointer-member-access (§18.5.2) ending with a type-argument-list (§4.4.1), the token immediately following the closing>
token is examined, to see if it is
- Biri
( ) ] } : ; , . ? == != | ^ && || & [
; veyaOne of( ) ] } : ; , . ? == != | ^ && || & [
; or- İlişkisel işleçlerden biri
< > <= >= is as
veyaOne of the relational operators< > <= >= is as
; or- Sorgu ifadesinin içinde görünen bağlamsal sorgu anahtar sözcüğü; veyaA contextual query keyword appearing inside a query expression; or
- Belirli bağlamlarda tanımlayıcıyı Kesinleştirme belirteci olarak değerlendiririz.In certain contexts, we treat identifier as a disambiguating token. Bu bağlamlar, ayırt edilen belirteçlerin sırasının,
is
case
out
bir tanımlama sözcüğünün ilk öğesi ayrıştırılırken (Bu durumda, belirteçlerin önünde veya önüne alındığı(
:
bir,
) ya da bir demet sabit değerinin sonraki bir öğesi olan anahtar sözcüklerden yalnızca biri tarafından hemen öncesinde, veya ya da ortaya çıkar.Those contexts are where the sequence of tokens being disambiguated is immediately preceded by one of the keywordsis
,case
orout
, or arises while parsing the first element of a tuple literal (in which case the tokens are preceded by(
or:
and the identifier is followed by a,
) or a subsequent element of a tuple literal.Aşağıdaki belirteç bu liste veya böyle bir bağlamdaki bir tanımlayıcı arasında ise, tür bağımsız değişken listesi basit ad, üye erişimi veya işaretçi üye erişiminin bir parçası olarak korunur ve belirteçleri dizisinin diğer olası ayrıştırması atılır.If the following token is among this list, or an identifier in such a context, then the type-argument-list is retained as part of the simple-name, member-access or pointer-member-access and any other possible parse of the sequence of tokens is discarded. Aksi takdirde, tür bağımsız değişken listesi , belirteçlerin başka bir olası ayrıştırması olmasa bile, basit ad, üye erişimi veya işaretçi-üye erişiminin bir parçası olarak kabul edilmez.Otherwise, the type-argument-list is not considered to be part of the simple-name, member-access or pointer-member-access, even if there is no other possible parse of the sequence of tokens. Bir ad alanı-veya-tür adı (§ 3,8) içinde bir tür bağımsız değişken listesi ayrıştırılırken bu kuralların uygulanmadığını unutmayın.Note that these rules are not applied when parsing a type-argument-list in a namespace-or-type-name (§3.8).
Bu tekliften kaynaklanan değişiklikler kesiliyorBreaking changes due to this proposal
Bu önerilen Kesinleştirme kuralı nedeniyle hiçbir bozucu değişiklik bilinmiyor.No breaking changes are known due to this proposed disambiguation rule.
İlginç örneklerInteresting examples
Bu Kesinleştirme kurallarının ilginç sonuçları aşağıda verilmiştir:Here are some interesting results of these disambiguation rules:
İfade, (A < B, C > D)
her bir karşılaştırma olmak üzere iki öğe içeren bir tanımlama grubu.The expression (A < B, C > D)
is a tuple with two elements, each a comparison.
İfade, (A<B,C> D, E)
ilki bir bildirim ifadesi olan iki öğesi olan bir tanımlama grubu olur.The expression (A<B,C> D, E)
is a tuple with two elements, the first of which is a declaration expression.
Çağrının M(A < B, C > D, E)
üç bağımsız değişkeni vardır.The invocation M(A < B, C > D, E)
has three arguments.
Çağrının, M(out A<B,C> D, E)
ilki bir bildirim olan iki bağımsız değişkeni vardır out
.The invocation M(out A<B,C> D, E)
has two arguments, the first of which is an out
declaration.
İfade e is A<B> C
bir bildirim ifadesi kullanır.The expression e is A<B> C
uses a declaration expression.
Case etiketi case A<B> C:
bir bildirim ifadesi kullanır.The case label case A<B> C:
uses a declaration expression.
Bazı kalıp eşleme örnekleriSome examples of pattern matching
Is-AsIs-As
Deyim yerini alacakWe can replace the idiom
var v = expr as Type;
if (v != null) {
// code using v
}
Biraz daha kısa ve doğrudanWith the slightly more concise and direct
if (expr is Type v) {
// code using v
}
Null yapılabilir testTesting nullable
Deyim yerini alacakWe can replace the idiom
Type? v = x?.y?.z;
if (v.HasValue) {
var value = v.GetValueOrDefault();
// code using value
}
Biraz daha kısa ve doğrudanWith the slightly more concise and direct
if (x?.y?.z is Type value) {
// code using value
}
Aritmetik basitleştirmeArithmetic simplification
İfadeleri göstermek için özyinelemeli türler kümesi tanımladığımızda (ayrı bir teklife göre):Suppose we define a set of recursive types to represent expressions (per a separate proposal):
abstract class Expr;
class X() : Expr;
class Const(double Value) : Expr;
class Add(Expr Left, Expr Right) : Expr;
class Mult(Expr Left, Expr Right) : Expr;
class Neg(Expr Value) : Expr;
Artık bir ifadenin türevini (azaltılan) hesaplamak için bir işlev tanımlayabiliriz:Now we can define a function to compute the (unreduced) derivative of an expression:
Expr Deriv(Expr e)
{
switch (e) {
case X(): return Const(1);
case Const(*): return Const(0);
case Add(var Left, var Right):
return Add(Deriv(Left), Deriv(Right));
case Mult(var Left, var Right):
return Add(Mult(Deriv(Left), Right), Mult(Left, Deriv(Right)));
case Neg(var Value):
return Neg(Deriv(Value));
}
}
Bir ifade simplifier konumsal desenleri gösterir:An expression simplifier demonstrates positional patterns:
Expr Simplify(Expr e)
{
switch (e) {
case Mult(Const(0), *): return Const(0);
case Mult(*, Const(0)): return Const(0);
case Mult(Const(1), var x): return Simplify(x);
case Mult(var x, Const(1)): return Simplify(x);
case Mult(Const(var l), Const(var r)): return Const(l*r);
case Add(Const(0), var x): return Simplify(x);
case Add(var x, Const(0)): return Simplify(x);
case Add(Const(var l), Const(var r)): return Const(l+r);
case Neg(Const(var k)): return Const(-k);
default: return e;
}
}