AralıklarRanges

ÖzetSummary

Bu özellik, oluşturma ve nesneleri sağlayan iki yeni işleç teslim etmek ve bunları çalışma zamanında System.Index System.Range dizin/dilim koleksiyonları için kullanmakla ilgilidir.This feature is about delivering two new operators that allow constructing System.Index and System.Range objects, and using them to index/slice collections at runtime.

Genel BakışOverview

İyi bilinen türler ve üyelerWell-known types and members

ve için yenintactic formlarını kullanmak üzere, hangintactic formların kullanıldıklarına bağlı olarak, yeni iyi bilinen System.Index System.Range türler ve üyeler gerekli olabilir.To use the new syntactic forms for System.Index and System.Range, new well-known types and members may be necessary, depending on which syntactic forms are used.

"hat" işleci () ^ kullanmak için aşağıdakiler gereklidirTo use the "hat" operator (^), the following is required

namespace System
{
    public readonly struct Index
    {
        public Index(int value, bool fromEnd);
    }
}

Türü bir System.Index dizi öğesi erişiminde bağımsız değişken olarak kullanmak için aşağıdaki üye gereklidir:To use the System.Index type as an argument in an array element access, the following member is required:

int System.Index.GetOffset(int length);

söz .. System.Range dizimi için System.Range türün yanı sıra aşağıdaki üyelerden biri veya daha fazlası gerekir:The .. syntax for System.Range will require the System.Range type, as well as one or more of the following members:

namespace System
{
    public readonly struct Range
    {
        public Range(System.Index start, System.Index end);
        public static Range StartAt(System.Index start);
        public static Range EndAt(System.Index end);
        public static Range All { get; }
    }
}

Söz .. dizimi, bağımsız değişkenlerinin her ikisini birden veya hiçbirinin eksik olmasına izin verir.The .. syntax allows for either, both, or none of its arguments to be absent. Bağımsız değişken sayısından bağımsız olarak oluşturucu söz Range dizimi kullanmak için her zaman Range yeterlidir.Regardless of the number of arguments, the Range constructor is always sufficient for using the Range syntax. Ancak, diğer üyelerden herhangi biri varsa ve bağımsız değişkenlerden biri veya .. daha fazlası eksikse, uygun üyenin yerini alan üye olabilir.However, if any of the other members are present and one or more of the .. arguments are missing, the appropriate member may be substituted.

Son olarak, bir dizi öğesi erişim ifadesinde kullanılacak türünde bir System.Range değer için aşağıdaki üyenin mevcut olması gerekir:Finally, for a value of type System.Range to be used in an array element access expression, the following member must be present:

namespace System.Runtime.CompilerServices
{
    public static class RuntimeHelpers
    {
        public static T[] GetSubArray<T>(T[] array, System.Range range);
    }
}

System.IndexSystem.Index

C# bir koleksiyonun en baştan dizin oluşturması için bir yol yoktur, ancak çoğu dizinci "başlangıç" ifadesini kullanır veya bir "uzunluk - i" ifadesi kullanır.C# has no way of indexing a collection from the end, but rather most indexers use the "from start" notion, or do a "length - i" expression. " Ucundan" anlamına gelen yeni bir Dizin ifadesi tanıtıyoruz.We introduce a new Index expression that means "from the end". Özellik, yeni birli ön ek "hat" işleci tanıtacak.The feature will introduce a new unary prefix "hat" operator. Tek işleneni' olarak System.Int32 dönüştürülebilir.Its single operand must be convertible to System.Int32. Uygun fabrika yöntemi çağrısına System.Index indirecek.It will be lowered into the appropriate System.Index factory method call.

Aşağıdaki ek söz dizimi unary_expression dil bilgisini geliştirin:We augment the grammar for unary_expression with the following additional syntax form:

unary_expression
    : '^' unary_expression
    ;

Buna end işlecinden dizin çağrılır.We call this the index from end operator. işleçlerden önceden tanımlanmış dizin aşağıdaki gibidir:The predefined index from end operators are as follows:

System.Index operator ^(int fromEnd);

Bu işleç davranışı yalnızca sıfırdan büyük veya sıfıra eşit giriş değerleri için tanımlanır.The behavior of this operator is only defined for input values greater than or equal to zero.

Örnekler:Examples:

var array = new int[] { 1, 2, 3, 4, 5 };
var thirdItem = array[2];    // array[2]
var lastItem = array[^1];    // array[new Index(1, fromEnd: true)]

System.RangeSystem.Range

C# içinde koleksiyonların "aralıklarına" veya "dilimlerine" erişmek için sözdizmsel bir yol yoktur.C# has no syntactic way to access "ranges" or "slices" of collections. Genellikle kullanıcılar, bellek dilimlerini filtrelemek/çalıştırmak için karmaşık yapılar uygulamaya zorlar veya gibi LINQ yöntemlerine list.Skip(5).Take(2) başvurur.Usually users are forced to implement complex structures to filter/operate on slices of memory, or resort to LINQ methods like list.Skip(5).Take(2). ve diğer benzer türlerin ekleriyle, bu tür bir işlemi dil/çalışma zamanı içinde daha derin bir düzeyde desteklemek ve arabirimin birleştirilmiş hale sahip olmak System.Span<T> daha önemli hale gelir.With the addition of System.Span<T> and other similar types, it becomes more important to have this kind of operation supported on a deeper level in the language/runtime, and have the interface unified.

Dil, yeni bir aralık işleci x..y tanıtacak.The language will introduce a new range operator x..y. bu, iki ifadeyi kabul eden bir ikili düzeltme işlecidir.It is a binary infix operator that accepts two expressions. İşleci atlanabilir (aşağıdaki örneklerde) ve dönüştürülebilir olması System.Index gerekir.Either operand can be omitted (examples below), and they have to be convertible to System.Index. Uygun fabrika yöntemi çağrısına System.Range düşürülecek.It will be lowered to the appropriate System.Range factory method call.

Yeni bir öncelik düzeyi multiplicative_expression için C# dil bilgisi kurallarını aşağıdakilerle değiştiririz:We replace the C# grammar rules for multiplicative_expression with the following (in order to introduce a new precedence level):

range_expression
    : unary_expression
    | range_expression? '..' range_expression?
    ;

multiplicative_expression
    : range_expression
    | multiplicative_expression '*' range_expression
    | multiplicative_expression '/' range_expression
    | multiplicative_expression '%' range_expression
    ;

Aralık işlecinin tüm biçimleri aynı önceliğe sahip olur.All forms of the range operator have the same precedence. Bu yeni öncelik grubu, birli işleçlerden daha düşüktür ve çokplikli aritmetik işleçlerden daha yüksektir.This new precedence group is lower than the unary operators and higher than the multiplicative arithmetic operators.

işlecine .. range işleci çağrılır.We call the .. operator the range operator. Yerleşik aralık işleci kabaca bu formun yerleşik işlecinin çağrılma biçimine karşılık olarak anlaşılabilir:The built-in range operator can roughly be understood to correspond to the invocation of a built-in operator of this form:

System.Range operator ..(Index start = 0, Index end = ^0);

Örnekler:Examples:

var array = new int[] { 1, 2, 3, 4, 5 };
var slice1 = array[2..^3];    // array[new Range(2, new Index(3, fromEnd: true))]
var slice2 = array[..^3];     // array[Range.EndAt(new Index(3, fromEnd: true))]
var slice3 = array[2..];      // array[Range.StartAt(2)]
var slice4 = array[..];       // array[Range.All]

Ayrıca, çok boyutlu imzalar üzerinde tamsayıları ve dizinleri aşırı yükleme ihtiyacının önüne geçerek ' den örtülü System.Index System.Int32 bir dönüştürmeye sahip olmalıdır.Moreover, System.Index should have an implicit conversion from System.Int32, in order to avoid the need to overload mixing integers and indexes over multi-dimensional signatures.

Mevcut kitaplık türlerine Dizin ve Aralık desteği eklemeAdding Index and Range support to existing library types

Örtülü Dizin desteğiImplicit Index support

Dil, aşağıdaki ölçütlere uyan türler için tek parametreli bir Index örnek dizin üyesi sağlar:The language will provide an instance indexer member with a single parameter of type Index for types which meet the following criteria:

  • Tür Countable'dır.The type is Countable.
  • türü, bağımsız değişken olarak tek bir alan erişilebilir bir örnek int dizine sahip.The type has an accessible instance indexer which takes a single int as the argument.
  • Türün, birinci parametre olarak alan erişilebilir bir örnek Index dizine sahip değildir.The type does not have an accessible instance indexer which takes an Index as the first parameter. tek Index parametre olmalıdır veya kalan parametreler isteğe bağlı olmalıdır.The Index must be the only parameter or the remaining parameters must be optional.

türü, veya adlı bir özelliğine ve bir dönüş türüne sahipse Length Countable'dır. Count intA type is Countable if it has a property named Length or Count with an accessible getter and a return type of int. Dil, bu özelliği kullanarak türünde bir ifadeyi ifadenin noktasındaki bir ifadeye dönüştürmek için, türü Index int kullanmaya hiç gerek Index kalmadan kullanabilir.The language can make use of this property to convert an expression of type Index into an int at the point of the expression without the need to use the type Index at all. Hem hem de Length mevcut olması durumunda tercih Count Length edilir.In case both Length and Count are present, Length will be preferred. Daha sonra kolaylık sağlamak için, teklif veya temsil etmek Length için adını Count Length kullanır.For simplicity going forward, the proposal will use the name Length to represent Count or Length.

Bu tür türler için dil, formun bir dizin üyesi gibi davranır; burada, stil ek açıklamaları dahil olmak üzere tabanlı T this[Index index] T dizin int oluşturmanın dönüş türü ref olur.For such types, the language will act as if there is an indexer member of the form T this[Index index] where T is the return type of the int based indexer including any ref style annotations. Yeni üye, dizin oluşturma ile eşleşen get set erişilebilirliği olan ve int üyelerine sahip olur.The new member will have the same get and set members with matching accessibility as the int indexer.

Yeni dizin oluşturma, türün bağımsız değişkenine dönüştürülerek ve tabanlı dizine Index int çağrı yayarak int uygulanır.The new indexer will be implemented by converting the argument of type Index into an int and emitting a call to the int based indexer. Tartışma amacıyla örneğini kullan o receiver[expr] zaman.For discussion purposes, let's use the example of receiver[expr]. dönüştürmesi expr int aşağıdaki gibi gerçekleşir:The conversion of expr to int will occur as follows:

  • bağımsız değişkeni formda olduğunda ve ^expr2 türü expr2 int olduğunda, değerine receiver.Length - expr2 çevrilir.When the argument is of the form ^expr2 and the type of expr2 is int, it will be translated to receiver.Length - expr2.
  • Aksi takdirde, olarak expr.GetOffset(receiver.Length) çevrilir.Otherwise, it will be translated as expr.GetOffset(receiver.Length).

Bu, geliştiricilerin özelliği Index değişiklike gerek kalmadan mevcut türlerde kullanmalarını sağlar.This allows for developers to use the Index feature on existing types without the need for modification. Örneğin:For example:

List<char> list = ...;
var value = list[^1];

// Gets translated to
var value = list[list.Count - 1];

Yan receiver Length etkilerin yalnızca bir kez yürütülmelerini sağlamak için ve ifadeleri uygun şekilde taşmalarını sağlar.The receiver and Length expressions will be spilled as appropriate to ensure any side effects are only executed once. Örneğin:For example:

class Collection {
    private int[] _array = new[] { 1, 2, 3 };

    public int Length {
        get {
            Console.Write("Length ");
            return _array.Length;
        }
    }

    public int this[int index] => _array[index];
}

class SideEffect {
    Collection Get() {
        Console.Write("Get ");
        return new Collection();
    }

    void Use() {
        int i = Get()[^1];
        Console.WriteLine(i);
    }
}

Bu kod "3. Uzunluğu Al" yazacak.This code will print "Get Length 3".

Örtülü Aralık desteğiImplicit Range support

Dil, aşağıdaki ölçütlere uyan türler için tek parametreli bir Range örnek dizin üyesi sağlar:The language will provide an instance indexer member with a single parameter of type Range for types which meet the following criteria:

  • Tür Countable'dır.The type is Countable.
  • türü, türünde iki parametreye Slice sahip adlı erişilebilir bir üyeye int sahip.The type has an accessible member named Slice which has two parameters of type int.
  • Türün ilk parametre olarak tek bir alan örnek Range dizineci yok.The type does not have an instance indexer which takes a single Range as the first parameter. tek Range parametre olmalıdır veya kalan parametreler isteğe bağlı olmalıdır.The Range must be the only parameter or the remaining parameters must be optional.

Bu tür türler için dil, formun bir dizin üyesi gibi bağlanacak ve burada, stil ek açıklamalarını içeren yöntemin dönüş T this[Range range] T türü Slice ref olur.For such types, the language will bind as if there is an indexer member of the form T this[Range range] where T is the return type of the Slice method including any ref style annotations. Yeni üye ile eşleşen erişilebilirliği de Slice olacak.The new member will also have matching accessibility with Slice.

Tabanlı dizin oluşturma, adlı bir ifadeye bağlı olduğunda, ifade daha sonra yöntemine geçirilen iki değere Range receiver Range dönüştürülerek Slice düşürülecek.When the Range based indexer is bound on an expression named receiver, it will be lowered by converting the Range expression into two values that are then passed to the Slice method. Tartışma amacıyla örneğini kullan o receiver[expr] zaman.For discussion purposes, let's use the example of receiver[expr].

için ilk Slice bağımsız değişken, aralık türüne sahip ifade aşağıdaki şekilde dönüştürülerek elde edilir:The first argument of Slice will be obtained by converting the range typed expression in the following way:

  • exprformda olduğunda expr1..expr2 (atlanabilir) ve expr2 expr1 türü olduğunda, olarak int yalıtılır. expr1When expr is of the form expr1..expr2 (where expr2 can be omitted) and expr1 has type int, then it will be emitted as expr1.
  • exprformda olduğunda ^expr1..expr2 expr2 (atlanabilir) olarak yalıtılır. receiver.Length - expr1When expr is of the form ^expr1..expr2 (where expr2 can be omitted), then it will be emitted as receiver.Length - expr1.
  • exprformda olduğunda ..expr2 expr2 (atlanabilir) olarak yalıtılır. 0When expr is of the form ..expr2 (where expr2 can be omitted), then it will be emitted as 0.
  • Aksi takdirde, olarak expr.Start.GetOffset(receiver.Length) yayımlar.Otherwise, it will be emitted as expr.Start.GetOffset(receiver.Length).

Bu değer, ikinci bağımsız değişkenin hesaplanmasında yeniden Slice kullanılır.This value will be re-used in the calculation of the second Slice argument. Bunu yaparken olarak start adlandırılır.When doing so it will be referred to as start. ikinci bağımsız Slice değişkeni, aralık türüne sahip ifade aşağıdaki şekilde dönüştürülerek elde edilir:The second argument of Slice will be obtained by converting the range typed expression in the following way:

  • exprformda olduğunda expr1..expr2 (atlanabilir) ve expr1 expr2 türü olduğunda, olarak int yalıtılır. expr2 - startWhen expr is of the form expr1..expr2 (where expr1 can be omitted) and expr2 has type int, then it will be emitted as expr2 - start.
  • exprformda olduğunda expr1..^expr2 expr1 (atlanabilir) olarak yalıtılır. (receiver.Length - expr2) - startWhen expr is of the form expr1..^expr2 (where expr1 can be omitted), then it will be emitted as (receiver.Length - expr2) - start.
  • exprformda olduğunda expr1.. expr1 (atlanabilir) olarak yalıtılır. receiver.Length - startWhen expr is of the form expr1.. (where expr1 can be omitted), then it will be emitted as receiver.Length - start.
  • Aksi takdirde, olarak expr.End.GetOffset(receiver.Length) - start yayımlar.Otherwise, it will be emitted as expr.End.GetOffset(receiver.Length) - start.

Tüm yan etkilerin yalnızca bir kez yürütülmelerini sağlamak için , receiver Length ve expr ifadeleri uygun şekilde taşacak.The receiver, Length, and expr expressions will be spilled as appropriate to ensure any side effects are only executed once. Örneğin:For example:

class Collection {
    private int[] _array = new[] { 1, 2, 3 };

    public int Length {
        get {
            Console.Write("Length ");
            return _array.Length;
        }
    }

    public int[] Slice(int start, int length) {
        var slice = new int[length];
        Array.Copy(_array, start, slice, 0, length);
        return slice;
    }
}

class SideEffect {
    Collection Get() {
        Console.Write("Get ");
        return new Collection();
    }

    void Use() {
        var array = Get()[0..2];
        Console.WriteLine(array.Length);
    }
}

Bu kod "Get Length 2" (Uzunluğu Al 2) yazacak.This code will print "Get Length 2".

Dil, aşağıdaki bilinen türler için özel bir durum içerir:The language will special case the following known types:

  • string: Substring yöntemi yerine Slice kullanılır.string: the method Substring will be used instead of Slice.
  • array: System.Runtime.CompilerServices.RuntimeHelpers.GetSubArray yöntemi yerine Slice kullanılır.array: the method System.Runtime.CompilerServices.RuntimeHelpers.GetSubArray will be used instead of Slice.

AlternatiflerAlternatives

Yeni işleçler ( ^ ve .. ) ise syntactic şekerdir.The new operators (^ and ..) are syntactic sugar. İşlevsellik, ve fabrika yöntemlerine yapılan açık çağrılar tarafından uygulansa da çok daha ortak koda neden olur ve deneyim uygunsuz System.Index System.Range olur.The functionality can be implemented by explicit calls to System.Index and System.Range factory methods, but it will result in a lot more boilerplate code, and the experience will be unintuitive.

IL GösterimiIL Representation

Bu iki işleç, sonraki derleyici katmanlarında değişiklik olmayacak şekilde normal dizinleyici/yöntem çağrılarına düşürülecek.These two operators will be lowered to regular indexer/method calls, with no change in subsequent compiler layers.

Çalışma zamanı davranışıRuntime behavior

  • Derleyici, dizinleyicileri diziler ve dizeler gibi yerleşik türler için en iyi duruma getirmenin ve dizin oluşturmanın uygun mevcut yöntemlere düşürülerek düşürülerek.Compiler can optimize indexers for built-in types like arrays and strings, and lower the indexing to the appropriate existing methods.
  • System.Index negatif bir değerle oluşturulursa oluşturulur.System.Index will throw if constructed with a negative value.
  • ^0 atamaz, ancak sağlanabilir koleksiyonun/numaralanabilirnin uzunluğuna çevrilir.^0 does not throw, but it translates to the length of the collection/enumerable it is supplied to.
  • Range.All , ile benzerdir ve 0..^0 bu dizinler için kod çözme adımlarına sahip olabilir.Range.All is semantically equivalent to 0..^0, and can be deconstructed to these indices.

Dikkat edilmesi gerekenlerConsiderations

ICollection 'e göre dizin algılamayı AlgılaDetect Indexable based on ICollection

Bu davranış için ilham, koleksiyon başlatıcıları idi.The inspiration for this behavior was collection initializers. Bir özelliği kabul etmiş olduğunu iletmek için bir türün yapısını kullanma.Using the structure of a type to convey that it had opted into a feature. Koleksiyon Başlatıcıları türleri söz konusu olduğunda, arabirimi IEnumerable (genel olmayan) uygulayarak özelliği kabul edebilir.In the case of collection initializers types can opt into the feature by implementing the interface IEnumerable (non generic).

Bu teklif başlangıçta, türlerin ICollection dizinlenebilir olarak nitelendirmek için uygulanması gerekir.This proposal initially required that types implement ICollection in order to qualify as Indexable. Bu, birkaç özel durum gerektirse de:That required a number of special cases though:

  • ref struct: Bu arabirimler, Span<T> Dizin/Aralık desteği için idealdir.ref struct: these cannot implement interfaces yet types like Span<T> are ideal for index / range support.
  • string: uygulamaz ICollection ve bu, interface büyük maliyetli bir şekilde eklenemez.string: does not implement ICollection and adding that interface has a large cost.

Bu, anahtar türlerini desteklemek için özel büyük küçük harfe zaten ihtiyaç duymasıdır.This means to support key types special casing is already needed. Özel büyük küçük harf, string dil olarak diğer alanlarda ( foreach kıs, sabitler, vb.) bunu yaparken daha az ilginç bir değer. Özel büyük küçük harf, ref struct bütün bir tür sınıfına özel olarak büyük küçük harfe göre daha fazla.The special casing of string is less interesting as the language does this in other areas (foreach lowering, constants, etc ...). The special casing of ref struct is more concerning as it's special casing an entire class of types. Yalnızca dönüş türü olan adlı bir özelliğe sahip olmaları halinde dizinlenebilir olarak etiketlenir Count int .They get labeled as Indexable if they simply have a property named Count with a return type of int.

Göz önünde bulundurulduktan sonra, Count / Length bir dönüş türüne sahip bir özelliği olan herhangi bir türün int dizinlenebilir olduğunu varsayalım.After consideration the design was normalized to say that any type which has a property Count / Length with a return type of int is Indexable. Bu, ve dizileri için bile tüm özel büyük harfleri kaldırır string .That removes all special casing, even for string and arrays.

Yalnızca sayıyı AlgılaDetect just Count

Özellik adlarında algılama Count veya Length tasarımın bir bit olduğunu karmaşıklaştırır.Detecting on the property names Count or Length does complicate the design a bit. Çok sayıda tür hariç tutularak, standartlaştırmak için yalnızca bir tane seçilmesi yeterlidir:Picking just one to standardize though is not sufficient as it ends up excluding a large number of types:

  • Kullanım Length : System. Collections ve alt ad alanlarında oldukça çok her koleksiyonu dışlar.Use Length: excludes pretty much every collection in System.Collections and sub-namespaces. Bu, bunlardan türeme eğilimindedir ICollection ve bu nedenle uzunluğu tercih eder Count .Those tend to derive from ICollection and hence prefer Count over length.
  • Kullanım Count : string dışama, dizi Span<T> ve en ref struct tabanlı türlerUse Count: excludes string, arrays, Span<T> and most ref struct based types

Dizine eklenebilir türlerin ilk algılamasında daha karmaşıkma, diğer yönlerde basitleştirme tarafından belirlenir.The extra complication on the initial detection of Indexable types is outweighed by its simplification in other aspects.

Ad olarak dilim seçimiChoice of Slice as a name

Ad, Slice .net 'teki dilim stili işlemlerine yönelik standart adı olarak seçilmiştir.The name Slice was chosen as it's the de-facto standard name for slice style operations in .NET. Netcoreapp 2.1 'den itibaren tüm yayılma stili türleri, Slice Dilimleme işlemleri için adı kullanır.Starting with netcoreapp2.1 all span style types use the name Slice for slicing operations. Netcoreapp 2.1 'den önce bir örnek için aranacak örneklere örnek yok.Prior to netcoreapp2.1 there really aren't any examples of slicing to look to for an example. Gibi türler List<T> , ArraySegment<T> SortedList<T> Dilimleme için idealdir ancak türler eklendiğinde kavram yoktu.Types like List<T>, ArraySegment<T>, SortedList<T> would've been ideal for slicing but the concept didn't exist when types were added.

Bu nedenle, Slice tek örnek olarak, ad olarak seçilmiştir.Thus, Slice being the sole example, it was chosen as the name.

Dizin hedef türü dönüştürmeIndex target type conversion

Bir Dizin Oluşturucu ifadesinde dönüştürmeyi görüntülemenin bir başka yolu da Index hedef tür dönüştürmesi olarak belirlenir.Another way to view the Index transformation in an indexer expression is as a target type conversion. Bu, formun bir üyesi gibi bağlamak yerine return_type this[Index] , ' a bir hedef türü dönüştürme atar int .Instead of binding as if there is a member of the form return_type this[Index], the language instead assigns a target typed conversion to int.

Bu kavram, countable türlerinde tüm üye erişimlerde genelleştirilemez.This concept could be generalized to all member access on Countable types. Türüne sahip bir ifade bir Index örnek üye çağrısına bağımsız değişken olarak kullanıldığında ve alıcı Countable olduğunda, ifadeye hedef tür dönüştürmesi olur int .Whenever an expression with type Index is used as an argument to an instance member invocation and the receiver is Countable then the expression will have a target type conversion to int. Bu dönüştürmeye uygulanabilecek üye etkinleştirmeleri, Yöntemler, Dizin oluşturucular, özellikler, uzantı yöntemleri vb. içerir. Yalnızca oluşturucular, alıcısı olmadığı için hariç tutulur.The member invocations applicable for this conversion include methods, indexers, properties, extension methods, etc ... Only constructors are excluded as they have no receiver.

Hedef tür dönüştürme, türü olan herhangi bir ifade için aşağıdaki şekilde uygulanır Index .The target type conversion will be implemented as follows for any expression which has a type of Index. Tartışma amaçları için şu örneği kullanın receiver[expr] :For discussion purposes lets use the example of receiver[expr]:

  • exprBiçimi ^expr2 ve türü olduğunda expr2 int , öğesine çevrilir receiver.Length - expr2 .When expr is of the form ^expr2 and the type of expr2 is int, it will be translated to receiver.Length - expr2.
  • Aksi takdirde, olarak çevrilir expr.GetOffset(receiver.Length) .Otherwise, it will be translated as expr.GetOffset(receiver.Length).

receiver Length Yan etkilerin yalnızca bir kez yürütüldüğünden emin olmak için, ve ifadeleri uygun şekilde taşacaktır.The receiver and Length expressions will be spilled as appropriate to ensure any side effects are only executed once. Örneğin:For example:

class Collection {
    private int[] _array = new[] { 1, 2, 3 };

    public int Length {
        get {
            Console.Write("Length ");
            return _array.Length;
        }
    }

    public int GetAt(int index) => _array[index];
}

class SideEffect {
    Collection Get() {
        Console.Write("Get ");
        return new Collection();
    }

    void Use() {
        int i = Get().GetAt(^1);
        Console.WriteLine(i);
    }
}

Bu kod "Get length 3" olarak yazdırılır.This code will print "Get Length 3".

Bu özellik, bir dizini temsil eden bir parametreye sahip olan herhangi bir üyeye faydalı olabilir.This feature would be beneficial to any member which had a parameter that represented an index. Örneğin, List<T>.InsertAt.For example List<T>.InsertAt. Ayrıca, bir ifadenin dizin oluşturmak için tasarlanmış olup olmadığı konusunda hiçbir rehberlik veremediğinden, bu da karışıklığın potansiyelini de sağlar.This also has the potential for confusion as the language can't give any guidance as to whether or not an expression is meant for indexing. Tüm bu tür bir deyimi, bir Index int Countable türünde üye çağırırken öğesine dönüştürür.All it can do is convert any Index expression to int when invoking a member on a Countable type.

LarındanRestrictions:

  • Bu dönüştürme yalnızca, türündeki ifade Index doğrudan üyenin bir bağımsız değişkeni olduğunda geçerlidir.This conversion is only applicable when the expression with type Index is directly an argument to the member. Herhangi bir iç içe geçmiş ifadeye uygulanmaz.It would not apply to any nested expressions.

Uygulama sırasında yapılan kararlarDecisions made during implementation

  • Düzendeki tüm Üyeler örnek üye olmalıdırAll members in the pattern must be instance members
  • Bir uzunluk yöntemi bulunursa ancak dönüş türü yanlış ise, sayı aramaya devam edinIf a Length method is found but it has the wrong return type, continue looking for Count
  • Dizin deseninin kullandığı dizin oluşturucunun tam olarak bir int parametresi olmalıdırThe indexer used for the Index pattern must have exactly one int parameter
  • Aralık deseninin kullandığı dilim yöntemi tam olarak iki int parametreye sahip olmalıdırThe Slice method used for the Range pattern must have exactly two int parameters
  • Model üyelerini ararken, oluşturulan üyeleri değil, özgün tanımları aradıkWhen looking for the pattern members, we look for original definitions, not constructed members

Tasarım toplantılarıDesign meetings