Salt okunur başvurularReadonly references

  • [x] önerilir[x] Proposed
  • [x] prototipi[x] Prototype
  • [x] uygulama: başlatıldı[x] Implementation: Started
  • [] Belirtimi: başlatılmadı[ ] Specification: Not Started

ÖzetSummary

"Salt okunur başvurular" özelliği aslında değişkenleri başvuruya göre geçirme ve değişiklikler için verileri açığa çıkarmadan faydalanma verimliliğini kullanan bir özellik grubudur:The "readonly references" feature is actually a group of features that leverage the efficiency of passing variables by reference, but without exposing the data to modifications:

  • in parametrelerein parameters
  • ref readonly döndürdüğüref readonly returns
  • readonly yapılarreadonly structs
  • ref/in Uzantı yöntemleriref/in extension methods
  • ref readonly ayarlanmalıdırref readonly locals
  • ref Koşullu ifadelerref conditional expressions

Bağımsız değişkenleri ReadOnly başvuruları olarak geçirme.Passing arguments as readonly references.

Bu konuya, https://github.com/dotnet/roslyn/issues/115 çok sayıda ayrıntıya geçmeden salt okunur parametreleri özel durum olarak dokunan mevcut bir teklif vardır.There is an existing proposal that touches this topic https://github.com/dotnet/roslyn/issues/115 as a special case of readonly parameters without going into many details. Burada yalnızca kendi fikrinin çok yeni olmayacağını bildirmek istiyorum.Here I just want to acknowledge that the idea by itself is not very new.

MotivasyonMotivation

Bu özellik C# ' den önce, hiçbir değişiklik yapmadan salt okunur amaçlar için yapı değişkenlerini metot çağrılarına geçirmeye yönelik etkili bir yola sahip değildir.Prior to this feature C# did not have an efficient way of expressing a desire to pass struct variables into method calls for readonly purposes with no intention of modifying. Normal değere sahip bağımsız değişken geçirme, gereksiz maliyetler ekleyen kopyalamayı gerektirir.Regular by-value argument passing implies copying, which adds unnecessary costs. Bu, kullanıcıların-ref bağımsız değişkenini kullanmasını ve verilerin aranan tarafından atlanması gerektiğini belirtmek için açıklamaları/belgeleri geçen ve kullanıcılara yönlendiren bir belge kullanır.That drives users to use by-ref argument passing and rely on comments/documentation to indicate that the data is not supposed to be mutated by the callee. Birçok nedenden dolayı iyi bir çözüm değildir.It is not a good solution for many reasons.
Örnek olarak, performans konuları nedeniyle, XNA gibi grafik kitaplıklarında çok sayıda vektör/matris matematik işleçleri başvuru işlenenleri olarak bilinir.The examples are numerous - vector/matrix math operators in graphics libraries like XNA are known to have ref operands purely because of performance considerations. Roslyn derleyicisinde, ayırmaların önüne geçmek için yapılar kullanan ve sonra maliyetleri kopyalamayı önlemek için bunları başvuruya göre ileten kod vardır.There is code in Roslyn compiler itself that uses structs to avoid allocations and then passes them by reference to avoid copying costs.

Çözüm ( in Parametreler)Solution (in parameters)

Parametrelere benzer şekilde out , in Parametreler, çağrılan ek garantilere göre yönetilen başvurular olarak geçirilir.Similarly to the out parameters, in parameters are passed as managed references with additional guarantees from the callee.
outDiğer herhangi bir kullanılmadan önce çağrılan tarafından atanması gereken parametrelerin aksine, in Parametreler hiçbir şekilde çağrılanın tarafından atanamaz.Unlike out parameters which must be assigned by the callee before any other use, in parameters cannot be assigned by the callee at all.

Sonuç olarak, bir sonuç olarak in , çağrılan bağımsız değişken geçirilen bağımsız değişkenler, çağıran tarafından birbirini tehlikeye atma ile ortaya çıkarmaz.As a result in parameters allow for effectiveness of indirect argument passing without exposing arguments to mutations by the callee.

inParametreleri bildirmeDeclaring in parameters

in parametreler in , anahtar sözcüğü parametre imzasında bir değiştirici olarak kullanılarak belirtilir.in parameters are declared by using in keyword as a modifier in the parameter signature.

Tüm amaçlar için in parametresi bir değişken olarak değerlendirilir readonly .For all purposes the in parameter is treated as a readonly variable. Yöntemi içindeki parametrelerin kullanımı ile ilgili kısıtlamaların çoğu in readonly alanlarla aynıdır.Most of the restrictions on the use of in parameters inside the method are the same as with readonly fields.

Gerçekten bir in parametre bir alanı temsil edebilir readonly .Indeed an in parameter may represent a readonly field. Kısıtlamaların benzerliği bir rastlantı değildir.Similarity of restrictions is not a coincidence.

Örneğin in , bir yapı türüne sahip bir parametrenin alan alanları, her yinelemeli olarak değişken olarak sınıflandırıldı readonly .For example fields of an in parameter which has a struct type are all recursively classified as readonly variables .

static Vector3 Add (in Vector3 v1, in Vector3 v2)
{
    // not OK!!
    v1 = default(Vector3);

    // not OK!!
    v1.X = 0;

    // not OK!!
    foo(ref v1.X);

    // OK
    return new Vector3(v1.X + v2.X, v1.Y + v2.Y, v1.Z + v2.Z);
}
  • in Parametreler, normal ByVal parametrelerine izin verildiğinde her yerde kullanılabilir.in parameters are allowed anywhere where ordinary byval parameters are allowed. Bu, Dizin oluşturucular, işleçler (dönüşümler dahil), temsilciler, Lambdalar, yerel işlevler içerir.This includes indexers, operators (including conversions), delegates, lambdas, local functions.
 (in int x) => x                                                     // lambda expression  
 TValue this[in TKey index];                                         // indexer
 public static Vector3 operator +(in Vector3 x, in Vector3 y) => ... // operator
  • in ile out birleştirilmeyecek hiçbir şeyle veya ile birlikte kullanılamaz out .in is not allowed in combination with out or with anything that out does not combine with.

  • Farklılıklara aşırı yükleme yapılmasına izin verilmez ref / out / in .It is not permitted to overload on ref/out/in differences.

  • Normal ByVal ve farklılıklara aşırı yükleme yapılmasına izin verilir in .It is permitted to overload on ordinary byval and in differences.

  • OHI (aşırı yükleme, gizleme, uygulama) amacıyla, in bir parametreye benzer şekilde davranır out .For the purpose of OHI (Overloading, Hiding, Implementing), in behaves similarly to an out parameter. Aynı kuralların hepsi geçerlidir.All the same rules apply. Örneğin, geçersiz kılma yönteminin in parametreleri in bir kimlik dönüştürülebilir türün parametreleriyle eşleşmesi gerekecektir.For example the overriding method will have to match in parameters with in parameters of an identity-convertible type.

  • Temsilci/Lambda/Yöntem grubu dönüştürmelerinde, in bir parametreye benzer şekilde davranır out .For the purpose of delegate/lambda/method group conversions, in behaves similarly to an out parameter. Lambdalar ve geçerli yöntem grubu dönüştürme adayları in , in kimlik dönüştürülebilir bir tür parametreleriyle hedef temsilcinin parametrelerini eşleştirmek zorunda kalacak.Lambdas and applicable method group conversion candidates will have to match in parameters of the target delegate with in parameters of an identity-convertible type.

  • Genel varyans amacına yönelik in Parametreler, değişken olmayan bir değişkendir.For the purpose of generic variance, in parameters are nonvariant.

NOTE: in başvuru veya temel türler içeren parametrelerde ilgili bir uyarı yok.NOTE: There are no warnings on in parameters that have reference or primitives types. Genel olarak daha az olabilir, ancak bazı durumlarda kullanıcının temel temelleri farklı şekilde geçirmek gerekir in .It may be pointless in general, but in some cases user must/want to pass primitives as in. Örnekler-olduğu gibi bir genel yöntemi geçersiz kılma Method(in T param) T int veya şunun gibi Yöntemler Volatile.Read(in int location)Examples - overriding a generic method like Method(in T param) when T was substituted to be int, or when having methods like Volatile.Read(in int location)

Parametrelerin verimsiz kullanımı konusunda uyaran bir çözümleyici Conceivable in , ancak bu tür analizler için kurallar bir dil belirtiminin parçası olmak için çok belirsiz olacaktır.It is conceivable to have an analyzer that warns in cases of inefficient use of in parameters, but the rules for such analysis would be too fuzzy to be a part of a language specification.

' In in çağrı sitelerinde kullanımı.Use of in at call sites. ( in bağımsız değişkenler)(in arguments)

Bağımsız değişkenleri parametrelere geçirmek için iki yol vardır in .There are two ways to pass arguments to in parameters.

in bağımsız değişkenler in parametrelerle eşleşiyor:in arguments can match in parameters:

Çağrı sitesinde değiştirici içeren bir bağımsız değişken in parametrelerle eşleştirebilir in .An argument with an in modifier at the call site can match in parameters.

int x = 1;

void M1<T>(in T x)
{
  // . . .
}

var x = M1(in x);  // in argument to a method

class D
{
    public string this[in Guid index];
}

D dictionary = . . . ;
var y = dictionary[in Guid.Empty]; // in argument to an indexer
  • in bağımsız değişken okunabilir bir lvalue (*) olmalıdır.in argument must be a readable LValue(*). Örnek: M1(in 42) geçersizExample: M1(in 42) is invalid

(*) Lvalue/rvalue kavramı diller arasında farklılık gösterir.(*) The notion of LValue/RValue vary between languages.
Burada, LValue tarafından doğrudan başvurulabilen bir konumu temsil eden bir ifade geliyor.Here, by LValue I mean an expression that represent a location that can be referred to directly. Ve RValue, kendi kendine kalıcı olmayan geçici bir sonuç veren bir ifade anlamına gelir.And RValue means an expression that yields a temporary result which does not persist on its own.

  • Özellikle readonly alanları, in parametreleri veya diğer resmi readonly değişkenleri in bağımsız değişken olarak geçirmek için geçerlidir.In particular it is valid to pass readonly fields, in parameters or other formally readonly variables as in arguments. Örnek: dictionary[in Guid.Empty] geçerlidir.Example: dictionary[in Guid.Empty] is legal. Guid.Empty statik salt okunur bir alandır.Guid.Empty is a static readonly field.

  • in bağımsız değişken, parametrenin türüne dönüştürülebilir olmalıdır.in argument must have type identity-convertible to the type of the parameter. Örnek: M1<object>(in Guid.Empty) geçersiz.Example: M1<object>(in Guid.Empty) is invalid. Guid.Emptykimlik-dönüştürülebilir değilobjectGuid.Empty is not identity-convertible to object

Yukarıdaki kurallara ilişkin mosyon, bağımsız in değişkenlerin bağımsız değişken değişkeninin diğer adını garanti eder.The motivation for the above rules is that in arguments guarantee aliasing of the argument variable. Aranan her zaman bağımsız değişkenle temsil edilen konuma bir doğrudan başvuru alır.The callee always receives a direct reference to the same location as represented by the argument.

  • inbağımsız değişkenlerin yığın await olarak, aynı çağrının işlenenleri olarak kullanılan ifadeler nedeniyle yığın olarak bir arada olması gerektiğinde, bu davranış ile out ve bağımsız değişkenlerle aynıdır. değişken, zaman uyumlu olarak ref saydam bir şekilde şeffaf bir şekilde çıkarılamıyor, bir hata bildirilir.in rare situations when in arguments must be stack-spilled due to await expressions used as operands of the same call, the behavior is the same as with out and ref arguments - if the variable cannot be spilled in referentially-transparent manner, an error is reported.

Örnekler:Examples:

  1. M1(in staticField, await SomethingAsync()) geçerli.M1(in staticField, await SomethingAsync()) is valid. staticField , observable yan etkileri olmadan birden çok kez erişilebilen statik bir alandır.staticField is a static field which can be accessed more than once without observable side effects. Bu nedenle, yan etkileri ve diğer ad gereksinimlerinin sırası belirtilebilir.Therefore both the order of side effects and aliasing requirements can be provided.
  2. M1(in RefReturningMethod(), await SomethingAsync()) bir hata üretir.M1(in RefReturningMethod(), await SomethingAsync()) will produce an error. RefReturningMethod() bir ref döndürme yöntemidir.RefReturningMethod() is a ref returning method. Bir yöntem çağrısında observable yan etkileri olabilir, bu nedenle işlenenden önce değerlendirilmelidir SomethingAsync() .A method call may have observable side effects, therefore it must be evaluated before the SomethingAsync() operand. Ancak, çağrının sonucu await doğrudan başvuru gereksinimini olanaksız hale getirecek olan askıya alma noktası genelinde korunmayan bir başvurudur.However the result of the invocation is a reference that cannot be preserved across the await suspension point which make the direct reference requirement impossible.

Not: yığın atımı hatası, uygulamaya özgü sınırlamalar olarak kabul edilir.NOTE: the stack spilling errors are considered to be implementation-specific limitations. Bu nedenle, aşırı yükleme çözünürlüğü veya lambda çıkarımı üzerinde hiçbir etkisi yoktur.Therefore they do not have effect on overload resolution or lambda inference.

Sıradan ByVal bağımsız değişkenleri in parametrelerle eşleşiyor:Ordinary byval arguments can match in parameters:

Değiştiriciler olmadan normal bağımsız değişkenler in parametrelerle eşleşmeyebilir.Regular arguments without modifiers can match in parameters. Bu tür durumlarda bağımsız değişkenler, sıradan bir ByVal bağımsız değişkenleri ile aynı gevşek kısıtlamalara sahiptir.In such case the arguments have the same relaxed constraints as an ordinary byval arguments would have.

Bu senaryoya ilişkin işlem, in API 'lerdeki parametrelerin, bağımsız değişkenler doğrudan başvuru-EX olarak geçirilmezse Kullanıcı için nedeniyle ile sonuçlanmasına neden olabilir: değişmez değerler, hesaplanan veya await Ed sonuçlar veya daha belirli türlere sahip olan bağımsız değişkenler.The motivation for this scenario is that in parameters in APIs may result in inconveniences for the user when arguments cannot be passed as a direct reference - ex: literals, computed or await-ed results or arguments that happen to have more specific types.
Tüm bu durumlarda, bağımsız değişken değerini uygun bir yerel türde depolamanın ve yerel olarak bir bağımsız değişken olarak geçirerek oluşan basit bir çözüm vardır in .All these cases have a trivial solution of storing the argument value in a temporary local of appropriate type and passing that local as an in argument.
Bu tür ortak kod derleyicisi gereksinimini azaltmak için, in arama sitesinde değiştirici yoksa, gerekirse aynı dönüşümü gerçekleştirebilir.To reduce the need for such boilerplate code compiler can perform the same transformation, if needed, when in modifier is not present at the call site.

Bunlara ek olarak, işleçler veya genişletme yöntemlerinin çağrılması gibi bazı durumlarda, hiç bir in şekilde belirtmenin sözdizimsel bir yolu yoktur in .In addition, in some cases, such as invocation of operators, or in extension methods, there is no syntactical way to specify in at all. Tek başına, parametreleri eşleştiklerinde sıradan ByVal bağımsız değişkenlerinin davranışının belirtilmesini gerektirir in .That alone requires specifying the behavior of ordinary byval arguments when they match in parameters.

Özellikle:In particular:

  • RValues geçişi için geçerlidir.it is valid to pass RValues. Bu tür bir durumda geçici bir başvuru geçirilir.A reference to a temporary is passed in such case. Örnek:Example:
Print("hello");      // not an error.

void Print<T>(in T x)
{
  //. . .
}
  • örtük Dönüştürmelere izin verilir.implicit conversions are allowed.

Bu aslında RValue geçirme özel bir durumdurThis is actually a special case of passing an RValue

Bu tür bir durumda, geçici olarak bir dönüştürülmüş değer tutan bir başvuru geçirilir.A reference to a temporary holding converted value is passed in such case. Örnek:Example:

Print<int>(Short.MaxValue)     // not an error.
  • bir in Genişletme yönteminin alıcısında ( ref uzantı yöntemlerinin aksine), rvalues veya örtük Bu bağımsız değişken dönüştürmelerine izin verilir.in a case of a receiver of an in extension method (as opposed to ref extension methods), RValues or implicit this-argument-conversions are allowed. Bu tür bir durumda, geçici olarak bir dönüştürülmüş değer tutan bir başvuru geçirilir.A reference to a temporary holding converted value is passed in such case. Örnek:Example:
public static IEnumerable<T> Concat<T>(in this (IEnumerable<T>, IEnumerable<T>) arg)  => . . .;

("aa", "bb").Concat<char>()    // not an error.

Uzantı yöntemleri hakkında daha fazla bilgi ref / in Bu belgede daha fazla sunulmaktadır.More information on ref/in extension methods is provided further in this document.

  • işlenenler nedeniyle bağımsız değişken atımı await , gerekirse "değere göre" taşarakargument spilling due to await operands could spill "by-value", if necessary. Bağımsız değişkene doğrudan bir başvuru sağlamak, await bağımsız değişkenin değerinin bir kopyasının birleştirilmesi nedeniyle mümkün olmadığından, bunun yerineIn scenarios where providing a direct reference to the argument is not possible due to intervening await a copy of the argument's value is spilled instead.
    Örnek:Example:
M1(RefReturningMethod(), await SomethingAsync())   // not an error.

Yan etkili bir çağrının sonucu, askıya alma genelinde korunmayan bir başvurudur await , bunun yerine gerçek değeri içeren geçici bir olay korunur (normal bir ByVal parametre durumunda olduğu gibi).Since the result of a side-effecting invocation is a reference that cannot be preserved across await suspension, a temporary containing the actual value will be preserved instead (as it would in an ordinary byval parameter case).

Atlanan isteğe bağlı bağımsız değişkenlerOmitted optional arguments

inParametrenin varsayılan bir değer belirtmesi için izin verilir.It is permitted for an in parameter to specify a default value. Bu, karşılık gelen bağımsız değişkeni isteğe bağlı hale getirir.That makes the corresponding argument optional.

Çağrı sitesinde isteğe bağlı bağımsız değişkeni atlama, varsayılan değeri geçici olarak geçirme ile sonuçlanır.Omitting optional argument at the call site results in passing the default value via a temporary.

Print("hello");      // not an error, same as
Print("hello", c: Color.Black);

void Print(string s, in Color c = Color.Black)
{
    // . . .
}

Genel olarak diğer ad davranışıAliasing behavior in general

Tıpkı ref ve out değişkenleri gibi değişkenler, in var olan konumların başvuruları/diğer adları.Just like ref and out variables, in variables are references/aliases to existing locations.

Çağrılan tarafından bunlara yazma izni verilmediği sürece bir in parametreyi okumak diğer değerlendirmelere yan bir etkisi olarak farklı değerleri gözlemleyebilirsiniz.While callee is not allowed to write into them, reading an in parameter can observe different values as a side effect of other evaluations.

Örnek:Example:

static Vector3 v = Vector3.UnitY;

static void Main()
{
    Test(v);
}

static void Test(in Vector3 v1)
{
    Debug.Assert(v1 == Vector3.UnitY);
    // changes v1 deterministically (no races required)
    ChangeV();
    Debug.Assert(v1 == Vector3.UnitX);
}

static void ChangeV()
{
    v = Vector3.UnitX;
}

in yerel değişkenlerin parametreleri ve yakalanması.in parameters and capturing of local variables.

Lambda/zaman uyumsuz yakalama parametrelerinin amacı, in ve parametreleriyle aynı şekilde davranır out ref .For the purpose of lambda/async capturing in parameters behave the same as out and ref parameters.

  • in Parametreler bir kapanışda yakalanamazin parameters cannot be captured in a closure
  • in Yineleyici metotlarda parametrelere izin verilmiyorin parameters are not allowed in iterator methods
  • in zaman uyumsuz yöntemlerde parametrelere izin verilmezin parameters are not allowed in async methods

Geçici değişkenler.Temporary variables.

Parametre geçirmenin bazı kullanımları, in geçici bir yerel değişkenin dolaylı kullanımını gerektirebilir:Some uses of in parameter passing may require indirect use of a temporary local variable:

  • in bağımsız değişkenler her zaman, Call-site kullandığında doğrudan diğer adlar olarak geçirilir in .in arguments are always passed as direct aliases when call-site uses in. Geçici, böyle bir durumda hiçbir şekilde kullanılmaz.Temporary is never used in such case.
  • in çağrı sitesi kullanmıyorsa bağımsız değişkenlerin doğrudan takma adlar olması gerekmez in .in arguments are not required to be direct aliases when call-site does not use in. Bağımsız değişken bir LValue olmadığında geçici bir şekilde kullanılabilir.When argument is not an LValue, a temporary may be used.
  • in parametrenin varsayılan değeri olabilir.in parameter may have default value. Çağrı sitesinde karşılık gelen bağımsız değişken atlandığında, varsayılan değer geçici olarak geçirilir.When corresponding argument is omitted at the call site, the default value are passed via a temporary.
  • in bağımsız değişkenler, kimliği korumayan bulunanlar da dahil olmak üzere örtük Dönüştürmelere sahip olabilir.in arguments may have implicit conversions, including those that do not preserve identity. Geçici olarak bu durumlarda kullanılır.A temporary is used in those cases.
  • sıradan yapı çağrılarının alıcıları yazılabilir LValues (mevcut durum!) olamaz.receivers of ordinary struct calls may not be writeable LValues (existing case!). Geçici olarak bu durumlarda kullanılır.A temporary is used in those cases.

Geçiciler bağımsız değişkeninin yaşam süresi, Call-site ' ın en yakın çevreleme kapsamıyla eşleşir.The life time of the argument temporaries matches the closest encompassing scope of the call-site.

Geçici değişkenlerin biçimsel yaşam süresi, başvuruya göre döndürülen değişkenlerin kaçış analizini içeren senaryolarda anlam açısından önemlidir.The formal life time of temporary variables is semantically significant in scenarios involving escape analysis of variables returned by reference.

Parametrelerin meta veri temsili in .Metadata representation of in parameters.

System.Runtime.CompilerServices.IsReadOnlyAttributeBir ByRef parametresine uygulandığında, parametre bir parametre olduğu anlamına gelir in .When System.Runtime.CompilerServices.IsReadOnlyAttribute is applied to a byref parameter, it means that the parameter is an in parameter.

Ayrıca, yöntem soyut veya sanal ise, bu parametrelerin (ve yalnızca bu parametrelerin) imzası olmalıdır modreq[System.Runtime.InteropServices.InAttribute] .In addition, if the method is abstract or virtual, then the signature of such parameters (and only such parameters) must have modreq[System.Runtime.InteropServices.InAttribute].

Mosyon: Bu, parametreleri geçersiz kılan/uygulayan bir yöntem olması durumunda olduğundan emin olmak için yapılır in .Motivation: this is done to ensure that in a case of method overriding/implementing the in parameters match.

Temsilcilerin içindeki yöntemler için de aynı gereksinimler geçerlidir Invoke .Same requirements apply to Invoke methods in delegates.

Mosyon: Bu, mevcut derleyicilerin readonly temsilcileri oluştururken veya atarken yalnızca yoksaymasını sağlamaktır.Motivation: this is to ensure that existing compilers cannot simply ignore readonly when creating or assigning delegates.

ReadOnly başvurusuyla döndürülüyor.Returning by readonly reference.

MotivasyonMotivation

Bu alt özellik için mosyon, kabaca, kopyalamanın önlenme nedenlerinden in , ancak döndürülen tarafta yer alır.The motivation for this sub-feature is roughly symmetrical to the reasons for the in parameters - avoiding copying, but on the returning side. Bu özellikten önce, bir yöntem veya dizin oluşturucunun iki seçeneği vardır: 1) başvuruya göre geri dönün ve olası mutasyonların veya 2), kopyalama ile sonuçlanan değere göre döndürülür.Prior to this feature, a method or an indexer had two options: 1) return by reference and be exposed to possible mutations or 2) return by value which results in copying.

Çözüm ( ref readonly döndürür)Solution (ref readonly returns)

Özelliği, bir üyenin değişkenleri bir başvuruya göre geri almasına izin verir.The feature allows a member to return variables by reference without exposing them to mutations.

ref readonlyDöndürülen üyeleri bildirmeDeclaring ref readonly returning members

Dönüş imzasında değiştiriciler birleşimi ref readonly , üyenin salt okunur bir başvuru döndürdüğünü göstermek için kullanılır.A combination of modifiers ref readonly on the return signature is used to to indicate that the member returns a readonly reference.

Tüm amaçlar için bir ref readonly üye, readonly alanlar ve parametrelere benzer bir değişken olarak değerlendirilir readonly in .For all purposes a ref readonly member is treated as a readonly variable - similar to readonly fields and in parameters.

Örneğin ref readonly , bir yapı türüne sahip olan üyenin alanları özyinelemeli olarak değişken olarak sınıflandırıldı readonly .For example fields of ref readonly member which has a struct type are all recursively classified as readonly variables. -Bunları in bağımsız değişken olarak ref veya bağımsız değişken olarak geçirmek için izin verilir out .- It is permitted to pass them as in arguments, but not as ref or out arguments.

ref readonly Guid Method1()
{
}

Method2(in Method1()); // valid. Can pass as `in` argument.

Method3(ref Method1()); // not valid. Cannot pass as `ref` argument
  • ref readonly aynı yerlerde dönüşlerine izin verilir ref .ref readonly returns are allowed in the same places were ref returns are allowed. Bu, Dizin oluşturucular, temsilciler, Lambdalar, yerel işlevler içerir.This includes indexers, delegates, lambdas, local functions.

  • Açık/farkları aşırı yüklemeye izin verilmez ref / ref readonly .It is not permitted to overload on ref/ref readonly / differences.

  • Normal ByVal üzerinde aşırı yükleme ve ref readonly geri dönüş farklılıkları vardır.It is permitted to overload on ordinary byval and ref readonly return differences.

  • OHI (aşırı yükleme, gizleme, uygulama) amaçları için ref readonly benzer ancak farklıdır ref .For the purpose of OHI (Overloading, Hiding, Implementing), ref readonly is similar but distinct from ref. Örneğin, birini geçersiz kılan bir yöntem ref readonly , kendisi olmalıdır ref readonly ve kimlik dönüştürülebilir tür olmalıdır.For example the a method that overrides ref readonly one, must itself be ref readonly and have identity-convertible type.

  • Temsilci/Lambda/Yöntem grubu dönüştürmelerinde, ref readonly benzer ancak farklıdır ref .For the purpose of delegate/lambda/method group conversions, ref readonly is similar but distinct from ref. Lambdalar ve geçerli yöntem grubu dönüştürme adayları, ref readonly ref readonly kimlik dönüştürülebilir olan türün dönüşü ile hedef temsilcinin dönmesini eşleşmelidir.Lambdas and applicable method group conversion candidates have to match ref readonly return of the target delegate with ref readonly return of the type that is identity-convertible.

  • Genel varyans amacına uygun olmayan ref readonly dönüşlerdir.For the purpose of generic variance, ref readonly returns are nonvariant.

NOTE: ref readonly başvuru ya da ilkel türler içeren dönüşlerde uyarı yok.NOTE: There are no warnings on ref readonly returns that have reference or primitives types. Genel olarak daha az olabilir, ancak bazı durumlarda kullanıcının temel temelleri farklı şekilde geçirmek gerekir in .It may be pointless in general, but in some cases user must/want to pass primitives as in. Örnekler-olduğu gibi genel bir yöntemi geçersiz kılma ref readonly T Method() T int .Examples - overriding a generic method like ref readonly T Method() when T was substituted to be int.

Dönüşün verimsiz kullanımı durumlarında uyaran bir çözümleyici Conceivable ref readonly , ancak bu tür analizler için kurallar bir dil belirtiminin parçası olmak için çok belirsiz olacaktır.It is conceivable to have an analyzer that warns in cases of inefficient use of ref readonly returns, but the rules for such analysis would be too fuzzy to be a part of a language specification.

Üyelerden dönme ref readonlyReturning from ref readonly members

Yöntem gövdesinin içinde sözdizimi, normal ref döndürimiyle aynıdır.Inside the method body the syntax is the same as with regular ref returns. , readonly Kapsayan yönteminden çıkarsedilir.The readonly will be inferred from the containing method.

Mosyon, return ref readonly <expression> gereksizdir ve yalnızca readonly her zaman hatalara neden olacak bölümde uyuşmazlıkların yapılmasına izin verir.The motivation is that return ref readonly <expression> is unnecessary long and only allows for mismatches on the readonly part that would always result in errors. refAncak, bir şeyin kesin diğer ad ile ve değere göre geçirildiği diğer senaryolarla tutarlılık için gereklidir.The ref is, however, required for consistency with other scenarios where something is passed via strict aliasing vs. by value.

Parametrelerden farklı olarak in , ref readonly bir yerel kopya aracılığıyla hiçbir şekilde geri dönmeme döndürür.Unlike the case with in parameters, ref readonly returns never return via a local copy. Kopyanın bu tür bir uygulama döndürüldüğünde hemen mevcut olmaya başlayacağından emin olmak, daha az ve tehlikeli olur.Considering that the copy would cease to exist immediately upon returning such practice would be pointless and dangerous. Bu nedenle ref readonly , dönüş her zaman doğrudan referanslardır.Therefore ref readonly returns are always direct references.

Örnek:Example:

struct ImmutableArray<T>
{
    private readonly T[] array;

    public ref readonly T ItemRef(int i)
    {
        // returning a readonly reference to an array element
        return ref this.array[i];
    }
}

  • Bağımsız değişkeninin return ref lvalue olması gerekir (var olan kural)An argument of return ref must be an LValue (existing rule)
  • Bağımsız değişkeninin return ref "dönmesi için güvenli" olması gerekir (var olan kural)An argument of return ref must be "safe to return" (existing rule)
  • Üyesinin bir ref readonly bağımsız değişkeninin return ref yazılabilir olması gerekmez.In a ref readonly member an argument of return ref is not required to be writeable . Örneğin, bu tür üye başvuru alabilir-salt okunur bir alan veya parametrelerinden birini döndürür in .For example such member can ref-return a readonly field or one of its in parameters.

Kuralları döndürmek için güvenli.Safe to Return rules.

Başvuru kuralları için normal güvenli, salt okunur başvurulara de uygulanır.Normal safe to return rules for references will apply to readonly references as well.

Bir, bir ref readonly normal ref yerel/parametre/dönüşten elde edilebilir, ancak başka bir yoldan alınkullanılamayacağını unutmayın.Note that a ref readonly can be obtained from a regular ref local/parameter/return, but not the other way around. Aksi takdirde, ref readonly döndürmenin güvenliği, düzenli dönüşler için aynı şekilde algılanır ref .Otherwise the safety of ref readonly returns is inferred the same way as for regular ref returns.

Bu RValues 'un parametre olarak geçirilebilir in ve ref readonly bir daha fazla kurala ihtiyaç duyduğumuz için geri dönülebilecek şekilde düşünüldüğünde , başvuruya göre güvenli dönüşsüz-rvalues.Considering that RValues can be passed as in parameter and returned as ref readonly we need one more rule - RValues are not safe-to-return by reference.

Bir RValue bir parametreye bir parametre ile geçirildiğinde in ve sonra bir biçiminde geri döndürüldüğünde durumu göz önünde bulundurun ref readonly .Consider the situation when an RValue is passed to an in parameter via a copy and then returned back in a form of a ref readonly. Çağıran bağlamında, bu tür çağrının sonucu, yerel verilere yönelik bir başvurudur ve bu nedenle bu, döndürülmek üzere güvenli değildir.In the context of the caller the result of such invocation is a reference to local data and as such is unsafe to return. RValues değeri dönmek için güvenli olmadıktan sonra var olan kural #6 Bu durumu zaten işler.Once RValues are not safe to return, the existing rule #6 already handles this case.

Örnek:Example:

ref readonly Vector3 Test1()
{
    // can pass an RValue as "in" (via a temp copy)
    // but the result is not safe to return
    // because the RValue argument was not safe to return by reference
    return ref Test2(default(Vector3));
}

ref readonly Vector3 Test2(in Vector3 r)
{
    // this is ok, r is returnable
    return ref r;
}

Güncelleştirilmiş safe to return kurallar:Updated safe to return rules:

  1. yığındaki değişkenlere başvuruların dönmesi için güvenlidirrefs to variables on the heap are safe to return
  2. ref/in parametrelerinin döndürülmesi güvenli in Parametreler doğal olarak yalnızca ReadOnly olarak döndürülebilir.ref/in parameters are safe to return in parameters naturally can only be returned as readonly.
  3. Out parametrelerinin dönmesi güvenlidir (ancak zaten bugün olduğu gibi, kesinlikle atanması gerekir)out parameters are safe to return (but must be definitely assigned, as is already the case today)
  4. alıcının dönmesi güvenli olduğu sürece örnek struct alanları geri dönmek için güvenlidirinstance struct fields are safe to return as long as the receiver is safe to return
  5. ' this ', yapı üyelerinden dönmek için güvenli değildir'this' is not safe to return from struct members
  6. başka bir yöntemden döndürülen ref, bu yönteme biçimsel parametreler olarak geçirilen tüm ReFS/ıse 'nin dönmesi güvenli olduğu durumlarda döndürülür. Alıcının bir struct, Class veya genel bir tür parametresi olarak yazılmış olmasına bakılmaksızın, özellikle alıcı dönmek için güvenli hale gelir.a ref, returned from another method is safe to return if all refs/outs passed to that method as formal parameters were safe to return. Specifically it is irrelevant if receiver is safe to return, regardless whether receiver is a struct, class or typed as a generic type parameter.
  7. Rvalues, başvuruya göre dönmek için güvenli değildir. Özellikle RValues, parametrelere göre geçiş için güvenlidir.RValues are not safe to return by reference. Specifically RValues are safe to pass as in parameters.

NOTE: ref benzeri türler ve ref atamaları dahil edildiğinde yürütmeye gelen dönüşlerle ilgili ek kurallar vardır.NOTE: There are additional rules regarding safety of returns that come into play when ref-like types and ref-reassignments are involved. Kurallar ve üyeleri için aynı şekilde geçerlidir ref ref readonly ve bu nedenle burada bahsedilmez.The rules equally apply to ref and ref readonly members and therefore are not mentioned here.

Diğer ad davranışı.Aliasing behavior.

ref readonly Üyeler sıradan üyelerle aynı diğer ad davranışını ref (ReadOnly olması dışında) sağlar.ref readonly members provide the same aliasing behavior as ordinary ref members (except for being readonly). Bu nedenle, Lambdalar, zaman uyumsuz, yineleyiciler, yığın sıçraıcı vb. için yakalama amacına yöneliktir. aynı kısıtlamalar geçerlidir.Therefore for the purpose of capturing in lambdas, async, iterators, stack spilling etc... the same restrictions apply. Yani.- I.E. gerçek başvuruların yakalanmasının nedeni ve üye değerlendirmesinin yan yana etkili olması nedeniyle bu senaryolara izin verilmez.due to inability to capture the actual references and due to side-effecting nature of member evaluation such scenarios are disallowed.

ref readonlyDönüş, düzenli bir yazılabilir başvuru olarak kabul edilecek ve normal bir yapı yöntemlerinin alıcısı olduğunda bir kopya oluşturmak için izin verilir ve gereklidir this .It is permitted and required to make a copy when ref readonly return is a receiver of regular struct methods, which take this as an ordinary writeable reference. Tarihsel olarak, bu tür bir çağırmaları ReadOnly değişkenine uygulandığı her durumda yerel bir kopya yapılır.Historically in all cases where such invocations are applied to readonly variable a local copy is made.

Meta veri gösterimi.Metadata representation.

System.Runtime.CompilerServices.IsReadOnlyAttributeBir ByRef döndüren metodun dönüşe uygulandığında, yöntemin salt okunur bir başvuru döndürdüğü anlamına gelir.When System.Runtime.CompilerServices.IsReadOnlyAttribute is applied to the return of a byref returning method, it means that the method returns a readonly reference.

Ayrıca, bu yöntemlerin sonuç imzası (ve yalnızca bu yöntemler) olmalıdır modreq[System.Runtime.CompilerServices.IsReadOnlyAttribute] .In addition, the result signature of such methods (and only those methods) must have modreq[System.Runtime.CompilerServices.IsReadOnlyAttribute].

Mosyon: Bu, mevcut derleyicilerin readonly dönüşlerle yöntemleri çağırırken yalnızca yoksaymasını sağlamaktır ref readonlyMotivation: this is to ensure that existing compilers cannot simply ignore readonly when invoking methods with ref readonly returns

ReadOnly yapılarReadonly structs

Kısaca this Oluşturucu, bir parametre haricinde bir yapının tüm örnek üyelerinin parametresini yapan bir özellik in .In short - a feature that makes this parameter of all instance members of a struct, except for constructors, an in parameter.

MotivasyonMotivation

Derleyici, bir struct örneğindeki herhangi bir yöntem çağrısının örneği değiştireolabileceğini varsaymalıdır.Compiler must assume that any method call on a struct instance may modify the instance. Aslında yazılabilir bir başvuru yönteme parametre olarak geçirilir this ve bu davranışı tamamen sağlar.Indeed a writeable reference is passed to the method as this parameter and fully enables this behavior. Değişkenlerde bu tür çağırmaları sağlamak için readonly , çağırmaları geçici kopyalara uygulanır.To allow such invocations on readonly variables, the invocations are applied to temp copies. Bu, sezgisel hale gelebilir ve bazen kişilerin performans nedenleriyle iptal etmeye zorlar readonly .That could be unintuitive and sometimes forces people to abandon readonly for performance reasons.
Örnek: https://codeblog.jonskeet.uk/2014/07/16/micro-optimization-the-surprising-inefficiency-of-readonly-fields/Example: https://codeblog.jonskeet.uk/2014/07/16/micro-optimization-the-surprising-inefficiency-of-readonly-fields/

Parametreler için destek ekledikten in ve ref readonly daha sonra, salt okunur değişkenler daha yaygın hale gelediğinden, savunmaya yönelik kopyalama sorununu döndürmenizden sonraAfter adding support for in parameters and ref readonly returns the problem of defensive copying will get worse since readonly variables will become more common.

ÇözümSolution

readonlyYapı bildirimlerinde değiştiriciye izin verin, bu, this in oluşturucular hariç tüm yapı örneği yöntemlerinde parametre olarak değerlendirilmelidir.Allow readonly modifier on struct declarations which would result in this being treated as in parameter on all struct instance methods except for constructors.

static void Test(in Vector3 v1)
{
    // no need to make a copy of v1 since Vector3 is a readonly struct
    System.Console.WriteLine(v1.ToString());
}

readonly struct Vector3
{
    . . .

    public override string ToString()
    {
        // not OK!!  `this` is an `in` parameter
        foo(ref this.X);

        // OK
        return $"X: {X}, Y: {Y}, Z: {Z}";
    }
}

ReadOnly yapısının üyeleri hakkında kısıtlamalarRestrictions on members of readonly struct

  • ReadOnly yapısının örnek alanları salt okunur olmalıdır.Instance fields of a readonly struct must be readonly.
    Mosyon: yalnızca harici olarak yazılabilir ancak üyelere eklenebilir.Motivation: can only be written to externally, but not through members.
  • Salt okunur bir yapının örnek oto özellikleri salt al olmalıdır.Instance autoproperties of a readonly struct must be get-only.
    Mosyon: örnek alanlarında kısıtlamanın sonucu.Motivation: consequence of restriction on instance fields.
  • ReadOnly struct alan benzeri olayları bildiremeyebilir.Readonly struct may not declare field-like events.
    Mosyon: örnek alanlarında kısıtlamanın sonucu.Motivation: consequence of restriction on instance fields.

Meta veri gösterimi.Metadata representation.

System.Runtime.CompilerServices.IsReadOnlyAttributeDeğer türüne uygulandığında, türün bir olması anlamına gelir readonly struct .When System.Runtime.CompilerServices.IsReadOnlyAttribute is applied to a value type, it means that the type is a readonly struct.

Özellikle:In particular:

  • IsReadOnlyAttributeTürün kimliği önemli değildir.The identity of the IsReadOnlyAttribute type is unimportant. Aslında, gerekirse kapsayan derlemede derleyici tarafından gömülebilir.In fact it can be embedded by the compiler in the containing assembly if needed.

ref/in Uzantı yöntemleriref/in extension methods

Aslında mevcut bir teklif ( https://github.com/dotnet/roslyn/issues/165) ve buna karşılık gelen PROTOTIP PR ( https://github.com/dotnet/roslyn/pull/15650) .There is actually an existing proposal (https://github.com/dotnet/roslyn/issues/165) and corresponding prototype PR (https://github.com/dotnet/roslyn/pull/15650). Yalnızca bu fikrin tamamen yeni olduğunu bildirmek istiyorum.I just want to acknowledge that this idea is not entirely new. Bununla birlikte, bu ref readonly tür yöntemler hakkında en iyi şeyleri ortadan kaldırdığından ve rvalue alıcılarından ne yapabileceğiniz hakkında daha fazla bilgi için burada da geçerlidir.It is, however, relevant here since ref readonly elegantly removes the most contentious issue about such methods - what to do with RValue receivers.

Genel fikir, this tür bir yapı türü olarak bilindiğinde, uzantı yöntemlerinin parametreyi başvuruya göre geçirmesine olanak sağlar.The general idea is allowing extension methods to take the this parameter by reference, as long as the type is known to be a struct type.

public static void Extension(ref this Guid self)
{
    // do something
}

Bu tür uzantı yöntemlerini yazma nedenleri öncelikle şunlardır:The reasons for writing such extension methods are primarily:

  1. Alıcı büyük bir yapı olduğunda kopyalamayı önleyinAvoid copying when receiver is a large struct
  2. Yapı birimlerinde uzantı yöntemlerinin değiştirilmesine izin verAllow mutating extension methods on structs

Sınıflarda buna izin vermek istemediğimiz nedenlerThe reasons why we do not want to allow this on classes

  1. Çok sınırlı bir amaç olabilir.It would be of very limited purpose.
  2. Yöntem çağrısının, null çağrıdan sonra olmak üzere alıcı olmayan bir şekilde dönemeyeceği uzun bir bozar keser null .It would break long standing invariant that a method call cannot turn non-null receiver to become null after invocation.

Aslında, null null ya da veya tarafından açıkça atanmamışsa veya geçirilmediği halde değişken olmayan bir ref olmaz out .In fact, currently a non-null variable cannot become null unless explicitly assigned or passed by ref or out. Okunabilirliği veya diğer "Bu tür", "Bu bir null" analizinden büyük ölçüde yardımcı olur.That greatly aids readability or other forms of "can this be a null here" analysis. 3. Null koşullu erişimlerin "bir kez değerlendir" semantiğinin uzlanması zor olabilir.It would be hard to reconcile with "evaluate once" semantics of null-conditional accesses. Örnek: obj.stringField?.RefExtension(...) - stringField null denetimini anlamlı hale getirmek için bir kopyasını yakalamanız gerekir, ancak sonra this refextension içindeki atamalar alana geri yansıtılmaz.Example: obj.stringField?.RefExtension(...) - need to capture a copy of stringField to make the null check meaningful, but then assignments to this inside RefExtension would not be reflected back to the field.

Başvuruya göre ilk bağımsız değişkeni alan yapılar üzerinde uzantı yöntemleri bildirme yeteneği uzun süreli bir istek idi.An ability to declare extension methods on structs that take the first argument by reference was a long-standing request. Engellenmeden biri "alıcı LValue değilse ne olur?" idi.One of the blocking consideration was "what happens if receiver is not an LValue?".

  • Herhangi bir uzantı yönteminin statik bir yöntem olarak da çağrılacağından, bazı durumlarda belirsizlik çözümlenmenin tek yolu vardır.There is a precedent that any extension method could also be called as a static method (sometimes it is the only way to resolve ambiguity). RValue alıcılarının izin verilmemelidir.It would dictate that RValue receivers should be disallowed.
  • Öte yandan, yapı örneği yöntemleri dahil edildiğinde benzer durumlarda bir kopyaya çağrı yapma yöntemi vardır.On the other hand there is a practice of making invocation on a copy in similar situations when struct instance methods are involved.

"Örtük kopyalama" olmasının nedeni, yapı yöntemlerinin büyük çoğunluğunun, bunu belirtemediği sürece yapıyı gerçekten değiştirmeleridir.The reason why the "implicit copying" exists is because the majority of struct methods do not actually modify the struct while not being able to indicate that. Bu nedenle en pratik çözüm, yalnızca bir kopyaya çağrı yapmak için, ancak bu uygulama, çok fazla performans ve hatalara neden olduğu bilinmektedir.Therefore the most practical solution was to just make the invocation on a copy, but this practice is known for harming performance and causing bugs.

Artık parametrelerin kullanılabilirliğiyle in , bir uzantının amacı işaret etmek mümkündür.Now, with availability of in parameters, it is possible for an extension to signal the intent. Bu nedenle Conundrum, ref in Uzantılar, gerektiğinde örtük kopyalamaya izin verdiğinden yazılabilir alıcılarla çağrılması gerekmeden çözülebilir.Therefore the conundrum can be resolved by requiring ref extensions to be called with writeable receivers while in extensions permit implicit copying if necessary.

// this can be called on either RValue or an LValue
public static void Reader(in this Guid self)
{
    // do something nonmutating.
    WriteLine(self == default(Guid));
}

// this can be called only on an LValue
public static void Mutator(ref this Guid self)
{
    // can mutate self
    self = new Guid();
}

in Uzantılar ve genel türler.in extensions and generics.

refUzantı yöntemlerinin amacı, alıcıyı doğrudan veya üye değiştirici çağırarak çağırmak için kullanılır.The purpose of ref extension methods is to mutate the receiver directly or by invoking mutating members. Bu nedenle ref this T uzantılara T , bir struct olarak kısıtlanan sürece izin verilir.Therefore ref this T extensions are allowed as long as T is constrained to be a struct.

Diğer yandan in Uzantı yöntemleri, örtük kopyalamayı azaltmak için özellikle vardır.On the other hand in extension methods exist specifically to reduce implicit copying. Ancak, bir parametresinin tüm kullanımı in T bir arabirim üyesi aracılığıyla yapılmalıdır.However any use of an in T parameter will have to be done through an interface member. Tüm arabirim üyeleri değişikliğe karşı kabul edildiğinden, bu tür bir kullanım için bir kopya gerekir.Since all interface members are considered mutating, any such use would require a copy. -Kopyalamayı azaltmak yerine, efekt tersi olur.- Instead of reducing copying, the effect would be the opposite. in this T T Kısıtlamaların ne olursa olsun genel tür parametresi olduğunda bu nedenle izin verilmez.Therefore in this T is not allowed when T is a generic type parameter regardless of constraints.

Geçerli uzantı yöntemleri türleri (Recap):Valid kinds of extension methods (recap):

thisBir genişletme yönteminde aşağıdaki bildirim formlarına artık izin verilir:The following forms of this declaration in an extension method are now allowed:

  1. this T arg -normal ByVal uzantısı.this T arg - regular byval extension. (mevcut durum)(existing case)
  • T, başvuru türleri veya tür parametreleri de dahil olmak üzere herhangi bir tür olabilir.T can be any type, including reference types or type parameters. Örnek, çağrıdan sonra aynı değişken olacaktır.Instance will be the same variable after the call. Bu bağımsız değişken dönüştürme türünün örtük dönüştürmelerine izin verir.Allows implicit conversions of this-argument-conversion kind. , RValues üzerinde çağrılabilir.Can be called on RValues.

  • in this T self - in uzantının.in this T self - in extension. T gerçek bir yapı türü olmalıdır.T must be an actual struct type. Örnek, çağrıdan sonra aynı değişken olacaktır.Instance will be the same variable after the call. Bu bağımsız değişken dönüştürme türünün örtük dönüştürmelerine izin verir.Allows implicit conversions of this-argument-conversion kind. , RValues üzerinde çağrılabilir (gerekirse geçici bir durum üzerinde çağrılabilir).Can be called on RValues (may be invoked on a temp if needed).

  • ref this T self - ref uzantının.ref this T self - ref extension. T bir struct türü ya da bir struct olarak kısıtlanmış genel tür parametresi olmalıdır.T must be a struct type or a generic type parameter constrained to be a struct. Örnek, çağırma tarafından yazılmış olabilir.Instance may be written to by the invocation. Yalnızca kimlik dönüştürmelerine izin verir.Allows only identity conversions. Yazılabilir LValue üzerinde çağrılmalıdır.Must be called on writeable LValue. (bir geçici aracılığıyla hiçbir şekilde çağırılmaz).(never invoked via a temp).

Salt okunur başvuru yerelleri.Readonly ref locals.

Amacı.Motivation.

ref readonlyÜyeler tanıtıldıktan sonra, uygun tür yerel ile eşleştirilmeleri gereken kullanımı ortadan kaldırıldı.Once ref readonly members were introduced, it was clear from the use that they need to be paired with appropriate kind of local. Bir üyenin değerlendirilmesi yan etkileri oluşturabilir veya gözlemlenebilir, bu nedenle sonuç birden çok kez kullanılacaksa, depolanması gerekir.Evaluation of a member may produce or observe side effects, therefore if the result must be used more than once, it needs to be stored. Sıradan ref Yereller, bir başvuru atanmadığından buraya yardım etmez readonly .Ordinary ref locals do not help here since they cannot be assigned a readonly reference.

Çözümden.Solution.

Yerelleri bildirmek için izin verin ref readonly .Allow declaring ref readonly locals. Bu, yazılabilir olmayan yeni bir ref yereltür türüdür.This is a new kind of ref locals that is not writeable. Sonuç olarak ref readonly , Yereller yazma için bu değişkenleri ortaya çıkarmadan ReadOnly değişkenlerine başvuruları kabul edebilir.As a result ref readonly locals can accept references to readonly variables without exposing these variables to writes.

Yereller bildirme ve kullanma ref readonly .Declaring and using ref readonly locals.

Bu tür Yereller sözdizimi, ref readonly bildirim sitesinde (bu belirli sırada) değiştiriciler kullanır.The syntax of such locals uses ref readonly modifiers at declaration site (in that specific order). Sıradan Yereller 'e benzer şekilde ref , ref readonly Yereller, bildirimde ref-Initialized olmalıdır.Similarly to ordinary ref locals, ref readonly locals must be ref-initialized at declaration. Normal ref Yerellerden farklı olarak, ref readonly Yereller readonly in Parametreler, readonly alanlar, yöntemler gibi lvalues 'a başvurabilir ref readonly .Unlike regular ref locals, ref readonly locals can refer to readonly LValues like in parameters, readonly fields, ref readonly methods.

Tüm amaçlar için ref readonly yerel bir değişken olarak değerlendirilir readonly .For all purposes a ref readonly local is treated as a readonly variable. Kullanım üzerindeki kısıtlamaların çoğu readonly alanlarla veya in parametrelerle aynıdır.Most of the restrictions on the use are the same as with readonly fields or in parameters.

Örneğin in , bir yapı türüne sahip bir parametrenin alan alanları, her yinelemeli olarak değişken olarak sınıflandırıldı readonly .For example fields of an in parameter which has a struct type are all recursively classified as readonly variables .

static readonly ref Vector3 M1() => . . .

static readonly ref Vector3 M1_Trace()
{
    // OK
    ref readonly var r1 = ref M1();

    // Not valid. Need an LValue
    ref readonly Vector3 r2 = ref default(Vector3);

    // Not valid. r1 is readonly.
    Mutate(ref r1);

    // OK.
    Print(in r1);

    // OK.
    return ref r1;
}

Yereller kullanımıyla ilgili kısıtlamalar ref readonlyRestrictions on use of ref readonly locals

readonly ref readonly Yereller dışında, Yereller sıradan ref Yereller gibi davranır ve tam olarak aynı kısıtlamalara tabidir.Except for their readonly nature, ref readonly locals behave like ordinary ref locals and are subject to exactly same restrictions.
Örneğin, kapanışlarda yakalama ile ilgili kısıtlamalar, async Yöntemler veya safe-to-return analizde aynı şekilde, Yereller için de geçerlidir ref readonly .For example restrictions related to capturing in closures, declaring in async methods or the safe-to-return analysis equally applies to ref readonly locals.

Üçlü ref ifadeler.Ternary ref expressions. (diğer adıyla "şartlı LValues")(aka "Conditional LValues")

MotivasyonMotivation

Ve Yereller 'in kullanımı, bir ref ref readonly koşula bağlı olarak bir veya başka bir hedef değişkeni ile bu tür yerelleri bir veya daha fazla yerelden başlatmaya gerekUse of ref and ref readonly locals exposed a need to ref-initialize such locals with one or another target variable based on a condition.

Tipik bir geçici çözüm, şunun gibi bir yöntemi tanıtmaktadır:A typical workaround is to introduce a method like:

ref T Choice(bool condition, ref T consequence, ref T alternative)
{
    if (condition)
    {
         return ref consequence;
    }
    else
    {
         return ref alternative;
    }
}

Choice Tüm bağımsız değişkenlerin, sezgisel olmayan davranış ve hatalara yönelik olarak önde gelen çağrı sitesinde değerlendirilmesi gerektiğinden, bir Üçlü tam değiştirme değildir.Note that Choice is not an exact replacement of a ternary since all arguments must be evaluated at the call site, which was leading to unintuitive behavior and bugs.

Aşağıdakiler beklendiği gibi çalışmayacak:The following will not work as expected:

    // will crash with NRE because 'arr[0]' will be executed unconditionally
    ref var r = ref Choice(arr != null, ref arr[0], ref otherArr[0]);

ÇözümSolution

Bir koşula bağlı olarak LValue bağımsız değişkeninden birine başvuru olarak değerlendirilen, özel tür koşullu ifadeye izin verin.Allow special kind of conditional expression that evaluates to a reference to one of LValue argument based on a condition.

refÜçlü ifade kullanma.Using ref ternary expression.

refKoşullu ifade türü için sözdizimi<condition> ? ref <consequence> : ref <alternative>;The syntax for the ref flavor of a conditional expression is <condition> ? ref <consequence> : ref <alternative>;

Yalnızca normal koşullu ifade gibi <consequence> ya da <alternative> Boolean koşul ifadesinin sonucuna bağlı olarak değerlendirilir.Just like with the ordinary conditional expression only <consequence> or <alternative> is evaluated depending on result of the boolean condition expression.

Sıradan koşullu ifadenin aksine, ref koşullu ifade:Unlike ordinary conditional expression, ref conditional expression:

  • , <consequence> ve <alternative> değerlerinin lvalues olmasını gerektirir.requires that <consequence> and <alternative> are LValues.
  • ref koşullu ifadenin kendisi bir LValue veref conditional expression itself is an LValue and
  • ref hem hem de <consequence> <alternative> yazılabilir lvalues olduğunda koşullu ifade yazılabilirref conditional expression is writeable if both <consequence> and <alternative> are writeable LValues

Örnekler:Examples:
ref Üçlü, bir LValue ve başvuruya göre geçirilebilir/atanabilir/döndürülebilir.ref ternary is an LValue and as such it can be passed/assigned/returned by reference;

     // pass by reference
     foo(ref (arr != null ? ref arr[0]: ref otherArr[0]));

     // return by reference
     return ref (arr != null ? ref arr[0]: ref otherArr[0]);

LValue olarak da atanabilir.Being an LValue, it can also be assigned to.

     // assign to
     (arr != null ? ref arr[0]: ref otherArr[0]) = 1;

     // error. readOnlyField is readonly and thus conditional expression is readonly
     (arr != null ? ref arr[0]: ref obj.readOnlyField) = 1;

, Bir yöntem çağrısının alıcısı olarak kullanılabilir ve gerekirse kopyalamayı atlayabilirsiniz.Can be used as a receiver of a method call and skip copying if necessary.

     // no copies
     (arr != null ? ref arr[0]: ref otherArr[0]).StructMethod();

     // invoked on a copy.
     // The receiver is `readonly` because readOnlyField is readonly.
     (arr != null ? ref arr[0]: ref obj.readOnlyField).StructMethod();

     // no copies. `ReadonlyStructMethod` is a method on a `readonly` struct
     // and can be invoked directly on a readonly receiver
     (arr != null ? ref arr[0]: ref obj.readOnlyField).ReadonlyStructMethod();

ref Üçlü, normal (Ref değil) bağlamda de kullanılabilir.ref ternary can be used in a regular (not ref) context as well.

     // only an example
     // a regular ternary could work here just the same
     int x = (arr != null ? ref arr[0]: ref otherArr[0]);

BulunmaktadırDrawbacks

Başvurular ve salt okunur başvurular için gelişmiş desteğe karşı iki önemli bağımsız değişken görebiliyorum:I can see two major arguments against enhanced support for references and readonly references:

  1. Burada çözülen sorunlar çok eski.The problems that are solved here are very old. Özellikle de, var olan koda yardımcı olmadığından, neden daha önce bu dosyaları şimdi çözmektedir?Why suddenly solve them now, especially since it would not help existing code?

Yeni etki alanlarında kullanılan C# ve .net ' i bulduğumuz için bazı sorunlar daha belirgin hale gelir.As we find C# and .Net used in new domains, some problems become more prominent.
Hesaplama fazla kafaları hakkında ortalamaya göre daha kritik olan ortamlara örnek olarak, şunları ListelerimAs examples of environments that are more critical than average about computation overheads, I can list

  • hesaplamanın faturalandırılması ve yanıt verebildiği bulut/veri merkezi senaryoları rekabetçi bir avantajdır.cloud/datacenter scenarios where computation is billed for and responsiveness is a competitive advantage.
  • Gecikme sürelerinde geçici gerçek zamanlı gereksinimlere sahip Oyunlar/VR/ARGames/VR/AR with soft-realtime requirements on latencies

Bu özellik, bazı yaygın senaryolarda daha fazla gözlerine izin verirken tür-güvenlik gibi mevcut güçlerin hiçbirini etkilemez.This feature does not sacrifice any of the existing strengths such as type-safety, while allowing to lower overheads in some common scenarios.

  1. Çağrılan kuralların, sözleşmelerde ne zaman kabul eteceğimizi makul ölçüde garanti edebilir readonly mi?Can we reasonably guarantee that the callee will play by the rules when it opts into readonly contracts?

Kullanırken benzer bir güveniz var out .We have similar trust when using out. Yanlış uygulanması out belirtilmeyen davranışa neden olabilir, ancak gerçekte nadiren meydana gelir.Incorrect implementation of out can cause unspecified behavior, but in reality it rarely happens.

Resmi doğrulama kurallarının tanıdık getirilmesi, ref readonly güven sorununu daha da hafifletmeye devam edecektir.Making the formal verification rules familiar with ref readonly would further mitigate the trust issue.

AlternatiflerAlternatives

Asıl rekabet tasarımı gerçekten "hiçbir şey yapmaz".The main competing design is really "do nothing".

Çözümlenmemiş sorularUnresolved questions

Tasarım toplantılarıDesign meetings

https://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-02-22.md https://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-03-01.md https://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-08-28.md https://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-09-25.md https://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-09-27.mdhttps://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-02-22.md https://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-03-01.md https://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-08-28.md https://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-09-25.md https://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-09-27.md