Aracılığıyla paylaş


ref readonly parametreleri

Not

Bu makale bir özellik belirtimidir. Belirtim, özelliğin tasarım belgesi olarak görev alır. Önerilen belirtim değişikliklerini ve özelliğin tasarımı ve geliştirilmesi sırasında gereken bilgileri içerir. Bu makaleler, önerilen belirtim değişiklikleri son haline getirilene ve geçerli ECMA belirtimine dahil edilene kadar yayımlanır.

Özellik belirtimi ile tamamlanan uygulama arasında bazı tutarsızlıklar olabilir. Bu farklılıklar, ilgili dil tasarım toplantısı (LDM) notlarındakaydedilir.

Özellik belirtimlerini C# dil standardına benimseme işlemi hakkında daha fazla bilgi edinmek içinbelirtimleri makalesinde bulabilirsiniz.

Şampiyon sorunu: https://github.com/dotnet/csharplang/issues/6010

Özet

Parametre bildirim yeri değiştiricisi ref readonly iznine izin ver ve çağrı yeri kurallarını aşağıdaki gibi değiştir:

Çağrı yeri açıklaması ref parametresi ref readonly parametresi in parametresi out parametresi
ref Izin verilen İzin Verilen Uyarı Hata
in Hata İzin Verilen Izin verilen Hata
out Hata Hatası Hata Izin verilen
Ek açıklama yok Hata Uyarı Izin verilen Hata

(Mevcut kurallarda bir değişiklik olduğuna dikkat edin: in parametresi ref çağrı sitesi ek açıklamasıyla hata yerine uyarı üretir.)

Başvuru değeri kurallarını aşağıdaki gibi değiştirin:

Değer türü ref parametresi ref readonly parametresi in parametresi out parametresi
rvalue Hata Uyarı Izin verilen Hata
lvalue Izin verilen İzin Verilen Izin verilen Izin verilen

Burada lvalue bir değişken (yani konumu olan bir değer; yazılabilir/atanabilir olması gerekmez) ve rvalue herhangi bir değer türü anlamına gelir.

Motivasyon

C# 7.2 , salt okunur referansları geçirmek için in olarak parametreleri tanıttı. in parametreleri hem lvalue'lara hem de rvalue'lara izin verir ve çağrı alanında ek açıklama olmadan kullanılabilir. Ancak, parametrelerinden başvuruları yakalayan veya döndüren API'ler, rvalue’lara izin vermemek ve çağrı yerinde bir başvurunun yakalandığını belirtecek bazı göstergeler zorunlu kılmak istemektedir. ref readonly parametreleri, rvalue'larla veya çağrı alanında ek açıklama olmadan kullanıldığında uyarı vermeleri gibi durumlarda idealdir.

Ayrıca, sadece salt okunur başvurulara ihtiyaç duyan ve bu şekilde kullanan API’ler de vardır.

  • ref parametreler, in kullanılmaya başlanmadan önce tanıtıldığından ve in'ye geçiş kaynak ve ikili uyumsuzluğa yol açabilecek bir değişiklik olacağından, örneğin QueryInterfaceveya
  • in parametreleri, rvalue nesneleri onlara aktarmanın pek mantıklı olmadığı durumlarda bile salt okunur referansları kabul etmek için ReadOnlySpan<T>..ctor(in T value)veya
  • Gönderilen referansı değiştirmeseler bile, rvalue'ları kabul etmeyen ref parametreleri, örneğin Unsafe.IsNullRef.

Bu API'ler kullanıcıları bölmeden ref readonly parametrelerine geçiş yapabilir. İkili uyumluluk hakkında ayrıntılı bilgi için bkz. önerilen meta veri kodlama. Özellikle, değiştirme

  • refref readonly yalnızca sanal yöntemler için ikili uyumsuzluğa yol açacak bir değişiklik olabilir.
  • refin, sanal yöntemler için ikili uyum bozucu değişiklik olur, ancak kaynak uyum bozucu değişiklik olmaz (çünkü kurallar, yalnızca ref parametrelere geçirilen in bağımsız değişkenler için uyarı verecek şekilde değişir),
  • inref readonly büyük bir değişiklik olmayacaktır (ancak çağrı noktası açıklaması veya rvalue bir uyarıya yol açmaz).
    • Eski derleyici sürümlerini kullanan kullanıcılar için, bu bir kaynak uyumsuzluğu değişikliği olacaktır (çünkü ref readonly parametrelerini ref parametresi olarak yorumlayıp çağrı yerinde in'yi veya açıklama vermeden işlem yapmaya izin vermezler) ve LangVersion <= 11 olan yeni derleyici sürümleri için tutarlılık sağlamak amacıyla, ilgili bağımsız değişkenler ref readonly değiştiricisi ile geçilmediği sürece ref parametrelerin desteklenmeyeceğine dair bir hata iletisi verilecektir. Bunu unutmayın.

Ters yönde, değişen

  • ref readonlyref potansiyel olarak kaynak kodda bozucu bir değişiklik olabilir (yalnızca ref çağrı sitesi ek açıklaması kullanılmışsa ve yalnızca bağımsız değişkenlerde salt okunur başvurular kullanılmışsa) ve sanal yöntemler için ikili uyumluluğu bozabilecek bir değişiklik olabilir.
  • ref readonlyin kesici değişiklik olmaz (ancak ref çağrı noktası ek açıklaması uyarıya neden olur).

Yukarıda açıklanan kuralların yöntem imzaları için geçerli olduğunu, ancak temsilci imzaları için geçerli olmadığını unutmayın. Örneğin, bir temsilci imzasında ref'ın in olarak değiştirilmesi, kaynak kırıcı bir değişiklik olabilir (eğer bir kullanıcı bu temsilci türüne ref parametresine sahip bir yöntem atıyorsa, bu, API değişikliğinden sonra bir hata haline gelir).

Ayrıntılı tasarım

Genel olarak, bu teklifte açıkça değiştirilenler dışında, parametrelerine yönelik kurallar, teklif'te 'de parametreleri için belirtilenle aynıdır.

Parametre bildirimleri

Dil bilgisi değişiklikleri gerekmez. Parametreler için ref readonly değiştiricisine izin verilecek. Normal yöntemlerin dışında, dizin oluşturucu parametreleri (ref readonly gibi ancak inaksine) için ref izin verilir, ancak işleç parametreleri için izin verilmez (ref ancak inaksine).

ref readonly parametreleri için varsayılan parametre değerlerine bir uyarı ile izin verilir, çünkü bunlar rvalue'ları geçmeye eşdeğerdir. Bu, API yazarlarının varsayılan değerlere sahip in parametreleri kaynak hatalarına neden olmadan ref readonly parametrelerle değiştirmesine olanak tanır.

Değer tipine yönelik denetimler

ref parametreleri için ref readonly bağımsız değişken değiştiriciye izin verilse de, bunun değer türü denetimlerini etkilemediğini unutmayın, yani örneğin,

  • ref yalnızca atanabilir değerlerle kullanılabilir;
  • Salt-okunur başvuruları iletmek için bunun yerine in bağımsız değişken değiştiricisini kullanmak gerekir.
  • rvalue'ları geçirmek için hiçbir değiştirici kullanmamak gerekir (bu, ref readonlyaçıklandığı gibi, parametreleri için uyarıya yol açar).

Aşırı yükleme çözümü

Aşırı yükleme çözümlemesi,bu teklifin özetini tablo tarafından belirtildiği gibi /no çağrı sitesi ek açıklamalarının ve parametre değiştiricilerinin karıştırılmasına izin verir; örneğin, tüm izin verilen ve uyarı durumlar aşırı yükleme çözümlemesi sırasında olası adaylar olarak kabul edilir. Özellikle, in parametresine sahip yöntemlerin çağrıları, refolarak işaretlenmiş karşılık gelen bağımsız değişkenle eşleştirecek şekilde mevcut davranışta bir değişiklik meydana geldi; bu değişiklik LangVersion üzerinden sınırlandırılacaktır.

Ancak, ref readonly parametresine çağrı sitesi değiştiricisi olmayan bir bağımsız değişken geçirildiğinde verilen uyarı, parametrenin belirli bir koşulu karşılaması durumunda gizlenir.

  • bir uzantı yöntemi çağırmasında alıcı,
  • özel koleksiyon başlatıcı veya interpolasyonlu dize işleyicisinin bir parçası olarak örtük olarak kullanılır.

Değere göre aşırı yüklemeler, bağımsız değişken değiştiricisi olmaması durumunda (ref readonly parametrelerin aynı davranışa sahip olması) in aşırı yüklemeler yerine tercih edilir.

Yöntem dönüştürmeleri

Benzer şekilde, anonim işlevin [§10.7] ve yöntem grubu [§10.8] dönüştürmeleri için bu değiştiriciler uyumlu olarak kabul edilir (ancak farklı değiştiriciler arasında izin verilen dönüştürmeler uyarıyla sonuçlanıyor):

  • Hedef yöntemin ref readonly parametresinin temsilcinin in veya ref parametresiyle eşleşmesine izin verilir.
  • Hedef yöntemin in parametresinin, temsilcinin ref readonly parametresiyle eşleşmesine veya dil sürümüne bağlı olarak ref parametresiyle eşleşmesine izin verilir.
  • Not: Hedef yöntemin ref parametresi temsilcinin in veya ref readonly parametresiyle eşleşmesine izin verilmez.

Örneğin:

DIn dIn = (ref int p) => { }; // error: cannot match `ref` to `in`
DRef dRef = (in int p) => { }; // warning: mismatch between `in` and `ref`
DRR dRR = (ref int p) => { }; // error: cannot match `ref` to `ref readonly`
dRR = (in int p) => { }; // warning: mismatch between `in` and `ref readonly`
dIn = (ref readonly int p) => { }; // warning: mismatch between `ref readonly` and `in`
dRef = (ref readonly int p) => { }; // warning: mismatch between `ref readonly` and `ref`
delegate void DIn(in int p);
delegate void DRef(ref int p);
delegate void DRR(ref readonly int p);

işlev işaretçisi dönüştürmelerinin davranışında bir değişiklik olmadığını unutmayın. Hatırlatmak gerekirse, referans türü değiştiricileri arasında bir uyuşmazlık varsa örtük işlev işaretçisi dönüştürmelerine izin verilmez ve herhangi bir uyarı olmadan açık dönüşümlere her zaman izin verilir.

İmza eşleştirme

Tek bir türde bildirilen üyeler, imzada yalnızca ref/out/in/ref readonlyfarklılık gösteremez. İmza eşleştirmenin diğer amaçları için (ör. gizlenme veya geçersiz kılma), ref readonlyin değiştirici ile değiştirilebilir, ancak bu durum bildirim sitesinde [§7.6] uyarıyla sonuçlanabilir. Bu, partial bildirimini uygulamasıyla eşleştirirken ve kesme noktası imzası ile kesişen imzayla eşleştirirken geçerli değildir. İmzalar ikili uyumlu olmadığından, ref/in ve ref readonly/ref değiştirici çiftleri için geçersiz kılmada bir değişiklik olmadığını, bunların değiştirilemeyeceğini unutmayın. Tutarlılık için, aynı durum diğer imza eşleştirme amaçları için de geçerlidir (ör. gizleme).

Meta veri kodlama

Hatırlatmak gerekirse,

  • ref parametreleri düz byref türleri (IL'deT&) olarak yayılır),
  • in parametreleri, ref gibidir ve ayrıca System.Runtime.CompilerServices.IsReadOnlyAttributeile ek açıklama yapılır. C# 7.3 ve sonraki sürümlerde [in] ve sanalsa modreq(System.Runtime.InteropServices.InAttribute)ile de gönderilir.

ref readonly parametreleri [in] T&olarak gönderilir ve aşağıdaki öznitelikle ek açıklama eklenir:

namespace System.Runtime.CompilerServices
{
    [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
    public sealed class RequiresLocationAttribute : Attribute
    {
    }
}

Ayrıca, sanalsa, modreq(System.Runtime.InteropServices.InAttribute) parametreleriyle ikili uyumluluğu sağlamak için in ile birlikte gönderilirler. in parametrelerin aksine, meta veri boyutunu artırmaktan kaçınmak ve eski derleyici sürümlerinin [IsReadOnly] parametreleri ref readonly parametre olarak yorumlamasını sağlamak için ref readonly parametreleri için ref gösterilmeyeceğini unutmayın (ve bu nedenle refref readonly farklı derleyici sürümleri arasında bile kaynak kıran bir değişiklik olmayacaktır).

RequiresLocationAttribute, ad alanı ile nitelendirilmiş adıyla eşleştirilir ve eğer derlemeye daha önce dahil edilmemişse derleyici tarafından sentezlenir.

Özniteliğin kaynakta belirtilmesi, ParamArrayAttributebenzer şekilde bir parametreye uygulanırsa hata olur.

İşlev işaretçileri

İşlev işaretçilerinde, in parametreler modreq(System.Runtime.InteropServices.InAttribute) ile gönderilir (bkz. işlev işaretçileri teklifi). ref readonly parametreleri bu modreqolmadan, yerine modopt(System.Runtime.CompilerServices.RequiresLocationAttribute)ile gönderilir. Eski derleyici sürümleri modopt yoksayar ve bu nedenle ref readonly parametreleri ref parametreler olarak yorumlar (yukarıda açıklandığı gibi ref readonly parametreleri olan normal yöntemler için eski derleyici davranışıyla tutarlıdır) ve modopt tanıyan yeni derleyici sürümleri, ref readonly ve çağrılarısırasında uyarı göndermek üzere parametreleri tanımak için bunu kullanır. Eski derleyici sürümleriyle tutarlılığı sağlamak için, LangVersion <= 11 etiketini taşıyan yeni derleyici sürümleri, uygun bağımsız değişkenler ref readonly değiştiricisi ile gönderilmediği sürece ref parametrelerinin desteklenmediğine dair hatalar bildirecektir.

İşlev işaretçisi imzalarındaki değiştiricileri ortak API'lerin parçasıysa değiştirmenin ikili bir kesme olduğunu, bu nedenle ref veya inref readonlyolarak değiştirirken ikili bir kesme olacağını unutmayın. Ancak, normal yöntemlerle tutarlı olarak, işaretçi LangVersion <= 11 çağrı sitesi değiştiricisiyle çağrıldığında inref readonly değişikliği yapılırken yalnızca in olan arayanlar için bir kaynak kopması meydana gelir.

Uyumluluk bozucu değişiklikler

Aşırı yükleme çözümlemesindeki ref/in uyumsuzluk gevşemesi, aşağıdaki örnekte gösterildiği gibi bir davranışı bozan değişikliğe sebep oluyor.

class C
{
    string M(in int i) => "C";
    static void Main()
    {
        int i = 5;
        System.Console.Write(new C().M(ref i));
    }
}
static class E
{
    public static string M(this C c, ref int i) => "E";
}

C# 11'de çağrı E.M'e bağlanır, bu nedenle "E" yazdırılır. C# 12'de C.M'ın bağlanmasına bir uyarı ile izin verilir ve çünkü geçerli bir adayımız var, uzantı kapsamları aranmaz, bu nedenle "C" yazdırılır.

Aynı nedenle kaynakta hataya neden olan bir değişiklik de vardır. Aşağıdaki örnek C# 11'de "1" yazdırır, ancak C# 12'de belirsizlik hatası nedeniyle derlenemez.

var i = 5;
System.Console.Write(C.M(null, ref i));

interface I1 { }
interface I2 { }
static class C
{
    public static string M(I1 o, ref int x) => "1";
    public static string M(I2 o, in int x) => "2";
}

Yukarıdaki örnekler, yöntem çağrıları için kesintileri göstermektedir, ancak bunlara neden olan aşırı yükleme çözümlemesi değişikliklerinden kaynaklanıyorsa, benzer şekilde yöntem dönüştürmeleri için de tetiklenebilirler.

Alternatif

Parametre bildirimleri

API yazarları, yalnızca lvalue kabul etmek üzere tasarlanmış in parametrelerini özel bir öznitelikle ek açıklama ile işaretleyebilir ve yanlış kullanımları işaretlemek için bir çözümleyici sağlayabilir. Bu, API yazarlarının ref parametrelerini kullanarak rvalue'ları engellemek için kullanan mevcut API'lerin imzalarını değiştirmesine izin vermez. Yalnızca bir ref değişkenine erişimi olan API kullanıcılarının ref readonly elde etmek için ek çalışma yapması gerekir. Bu API'leri ref'dan [RequiresLocation] in'e değiştirmek, kaynakla uyumsuzluk yaratan bir değişiklik olur (ve eğer sanal yöntemler söz konusu ise ikili uyumsuzluk yaratan bir değişikliğe de neden olur).

değiştirici ref readonlyizin vermek yerine, derleyici özel bir özniteliğin ([RequiresLocation]gibi) bir parametreye ne zaman uygulandığını tanıyabilir. Bu, LDM 2022-04-25'de ele alınmıştı. Bunun çözümleyici değil dil özelliği olduğuna karar vererek, öyle görünmesi gerekir.

Değer türü denetimleri

C++'ın örtük byref parametrelerine benzer şekilde, ref readonly parametrelerine değiştirici olmadan lvalue geçirmesine hiçbir uyarı olmadan izin verilebiliyordu. Bu, LDM 2022-05-11bölümünde ele alınmıştı ve ref readonly parametreleri için birincil motivasyonun bu parametrelerden başvuruları yakalayan veya döndüren API'ler olduğuna dikkat çekerek, bu nedenle bir tür işaretçinin iyi bir şey olduğunu belirtmektedir.

Rvalue'nin bir ref readonly'a geçirilmesi, uyarı değil, hata olabilir. Bu, başlangıçta LDM 2022-04-25kabul edildi, ancak daha sonra e-posta tartışmaları bunu gevşetti çünkü mevcut API'leri kullanıcılara zarar vermeden değiştirme yeteneğimizi yitirdik.

in, ref readonly parametreleri için "doğal" çağrı sitesi değiştiricisi olabilir ve ref kullanılması uyarılara neden olabilir. Bu, tutarlı bir kod stili sağlar ve çağrı alanında başvurunun salt okunur olduğunu (refaksine) belirgin hale getirir. Başlangıçta LDM 2022-04-25kabul edildi. Ancak, uyarılar API yazarlarının ref'den ref readonlygeçişine yönelik bir uyuşma noktası olabilir. Ayrıca, inref readonly + kolaylık özellikleri olarak yeniden tanımlanmıştır, bu nedenle LDM 2022-05-11reddedildi.

LDM incelemesi bekleniyor

C# 12'de aşağıdaki seçeneklerden hiçbiri uygulanmadı. Potansiyel teklifler olarak kalıyor.

Parametre bildirimleri

Değiştiricilerin ters sırasına (readonly refyerineref readonly) izin verilebiliyor. Bu, readonly ref dönüşlerinin ve alanlarının davranışıyla (ters sıralamaya izin verilmez veya sırasıyla farklı bir şey anlamına gelir) tutarsız olur ve gelecekte uygulanırsa salt okunur parametrelerle çakışmaya neden olabilir.

Varsayılan parametre değerleri, ref readonly parametreleri için bir hata olabilir.

Değer türü denetimleri

ref readonly parametrelerine rvalue geçirildiğinde veya çağrı sitesi ek açıklamaları ile parametre değiştiricileri uyuşmadığında uyarılar yerine hatalar oluşabilir. Benzer şekilde, modreq parametrelerin ikili düzeydeki ref readonly parametrelerden ayrı olduğundan emin olmak için öznitelik yerine özel in kullanılabilir. Bu, daha güçlü garantiler sağlar, bu nedenle yeni API'ler için iyi olur, ancak çalışma zamanı esnasında kesinti yaratacak değişiklik yapamayan mevcut API'lerde benimsemeyi engeller.

Değer türü denetimleri, ref aracılığıyla salt okunur başvuruların in/ref readonly parametrelerine geçirilmesine izin verecek şekilde gevşetilebilir. Ref atamaları ve ref döndürmelerinin bugün çalıştığı şekle benzer olacaktır; ayrıca, kaynak ifadedeki ref değiştiricisi aracılığıyla başvuruların salt okunur olarak geçirilmesine de izin verir. Bununla birlikte, ref genellikle hedefin ref readonlyolarak tanımlandığı yere yakındır; bu, bağımsız değişken ve parametre değiştiricileri genellikle birbirinden çok uzakta olan çağrıların aksine, referansı salt okunur olarak geçtiğimizin açık olduğunu gösterir. Ayrıca, izin veren bağımsız değişkenlerden farklı olarak yalnızca değiştiriciyi izin verir, bu nedenle ve bağımsız değişkenler için değiştirilebilir hale gelir veya kullanıcılar kodlarını tutarlı hale getirmek isterse neredeyse kullanımdan kalkabilir (başvuru atamaları ve başvuru dönüşleri için izin verilen tek değiştirici olduğu için büyük olasılıkla her yerde kullanırlar).

Aşırı Yükleme Çözümü

Aşırı yükleme çözümlemesi, geçersiz kılma ve dönüştürme, ref readonly ve in değiştiricilerin değiştirilememesine izin verebilir.

Mevcut in parametreleri için aşırı yükleme çözümlemesindeki değişiklik LangVersion'a bakılmaksızın koşulsuz olarak alınabilir, ancak bu, mevcut işlevsellikte bozulmaya neden olan bir değişiklik olacaktır.

ref readonly alıcıyla bir uzantı yöntemini çağırmak, çağrı sitesi değiştiricisi olmayan uzantı dışı çağrılarda olduğu gibi "Bağımsız değişken 1 ref veya in anahtar sözcükle geçirilmelidir" uyarısına neden olabilir (kullanıcı, uzantı yöntemi çağırmasını statik yöntem çağrısına dönüştürerek bu uyarıyı düzeltebilir). Özel koleksiyon başlatıcısı veya ref readonly parametresiyle ilişkilendirilmiş dize işleyicisi kullanılırken aynı uyarı bildirilebilir, ancak kullanıcı bu sorunu gideremedi.

ref readonly aşırı yüklemeleri, bir çağrı sitesi değiştiricisi olmadığında veya bir belirsizlik hatası olduğunda değere göre aşırı yüklemeler yerine tercih edilebilir.

Yöntem dönüşümleri

Hedef yöntemin ref parametresinin temsilcinin in ve ref readonly parametresiyle eşleşmesine izin verebiliriz. Bu, API yazarlarının, normal yöntem imzaları için izin verilenlerle tutarlı bir şekilde, örneğin temsilci imzalarında refin olarak değiştirmesine ve kullanıcılarını bozmadan bu değişikliği yapmasına olanak tanır. Ancak, yalnızca bir uyarıyla aşağıdaki readonly garantilerinin ihlaline de neden olur:

class Program
{
    static readonly int f = 123;
    static void Main()
    {
        var d = (in int x) => { };
        d = (ref int x) => { x = 42; }; // warning: mismatch between `ref` and `in`
        d(f); // changes value of `f` even though it is `readonly`!
        System.Console.WriteLine(f); // prints 42
    }
}

İşlev işaretçisi dönüştürmeleri ref readonly/ref/in uyuşmazlığı konusunda uyarabilir, ancak bunu LangVersion'da kontrol altına almak isteseydik, tür dönüştürmelerinin bugün derlemeye erişmesi gerekmediğinden bu durum önemli bir uygulama yatırımı gerektirirdi. Ayrıca, uyuşmazlık şu anda bir hata olarak görülse de, kullanıcıların istedikleri takdirde bu uyuşmazlıklara izin vermek için kolayca bir tür dönüşüm eklemeleri mümkündür.

Metadata kodlama

RequiresLocationAttribute ve In özniteliklerine benzer şekilde kaynaktaki Out belirtilmesine izin verilebiliyor. Alternatif olarak, IsReadOnly özniteliğine benzer şekilde yalnızca parametrelerden farklı bağlamlarda uygulandığında bir hata olabilir; daha fazla tasarım alanı korumak için.

İşlev işaretçisi ref readonly parametreleri farklı modopt/modreq bileşimleriyle yayılabilir (bu tablodaki "kaynak sonunun" LangVersion <= 11olan arayanlar için anlamına geldiğini unutmayın):

Değiştiriciler Derlemeler arasında fark edilebilir Eski derleyiciler bunları şöyle görür: refref readonly inref readonly
modreq(In) modopt(RequiresLocation) evet in ikili, kaynak sonu ikili kesme
modreq(In) Hayır in ikili, kaynak sonu Tamam
modreq(RequiresLocation) evet Desteklenmeyen ikili, kaynak sonu ikili, kaynak sonu
modopt(RequiresLocation) evet ref ikili kesme ikili, kaynak sonu

[RequiresLocation] parametreleri için hem [IsReadOnly] hem de ref readonly öznitelikleri yayabiliriz. Daha sonra inref readonly, eski derleyici sürümleri için bile kırıcı bir değişiklik olmaz, ancak refref readonly, eski derleyici sürümleri için kaynak kırıcı değişiklik olur çünkü eski derleyici sürümleri ref readonlyinolarak yorumlar ve ref değiştiricilere izin vermez, yeni derleyici sürümleri ise LangVersion <= 11 tutarlılığı sağlamak amacıyla kaynak kırıcı değişiklik olarak değerlendirir.

LangVersion <= 11 davranışını eski derleyici sürümleri için davranıştan farklı hale getirebiliriz. Örneğin, bir ref readonly parametresi çağrıldığında (çağrı alanında ref değiştirici kullanılırken bile) bir hata oluşabilir veya herhangi bir hata olmadan her zaman buna izin verilir.

Hataya neden olan değişiklikler

Bu teklif, nadiren karşılaşılması gerektiğinden, LangVersion tarafından sınırlanmış olduğundan ve kullanıcıların uzantı yöntemini açıkça çağırarak bu değişikliği aşabilmesi için davranış değiştiren bir hatayı kabul etmeyi önerir. Bunun yerine, bunu şu şekilde azaltabiliriz:

  • ref / in uyumsuzluğuna izin verme (in henüz kullanılamadığından yalnızca ref kullanan eski API'ler için in geçişini engeller),
  • teklif edilen bu değişiklikle, bir referans türü uyuşmazlığı olduğunda, aşağıda belirtilen üstünlük kurallarına göre daha iyi bir eşleşme bulmak için aşırı yükleme çözümleme kurallarının değiştirilmesi,
    • veya alternatif olarak yalnızca ref ile in uyuşmazlığı için devam edin, diğerleri için değil (ref readonly vs. ref/in/değere göre).
İyilik hüküm sürer

Aşağıdaki örnek şu anda üç Mçağrısı için üç belirsizlik hatasına neden olur. Belirsizlikleri çözmek için yeni iyilik kuralları ekleyebiliriz. Bu, daha önce açıklanan kaynak kodunu bozan değişikliği de çözer. Bunun bir yolu, 221'ı örnek olarak yazdırmaktır. Burada, ref readonly parametresi in bağımsız değişkeniyle eşleştirilir çünkü in parametresi için izin verilirken, parametrenin değiştirici olmadan çağrılması bir uyarıya neden olur.

interface I1 { }
interface I2 { }
class C
{
    static string M(I1 o, in int i) => "1";
    static string M(I2 o, ref readonly int i) => "2";
    static void Main()
    {
        int i = 5;
        System.Console.Write(M(null, ref i));
        System.Console.Write(M(null, in i));
        System.Console.Write(M(null, i));
    }
}

Yeni iyileştirme kuralları, farklı bir bağımsız değişken değiştirici kullanılarak daha iyi hale getirilebilecek bir bağımsız değişkenle verilen parametreyi daha kötü olarak işaretleyebilir. Başka bir deyişle, kullanıcı her zaman ilgili bağımsız değişken değiştiricisini değiştirerek daha kötü bir parametreyi daha iyi bir parametreye dönüştürebilmelidir. Örneğin, bir bağımsız değişken intarafından geçirildiğinde, kullanıcı ref readonly parametresini seçmek için bağımsız değişkeni değere göre geçirebildiğinden in parametresi yerine bir in parametresi tercih edilir. Bu kural, bugün geçerli olan değere göre/in tercih kuralının bir uzantısıdır (bu son aşırı yükleme çözümleme kuralıdır ve parametresi daha iyiyse ve hiçbiri başka bir aşırı yüklemenin ilgili parametresinden daha kötü değilse tüm aşırı yükleme daha iyidir).

tartışma daha iyi parametre kötü parametre
ref/in ref readonly in
ref ref ref readonly/in
değere göre değere göre/in ref readonly
in in ref

Yöntem dönüştürmelerini benzer şekilde işlememiz gerekir. Aşağıdaki örnek şu anda iki temsilci ataması için iki belirsizlik hatasına neden olur. Yeni iyileştirme kuralları, refness değiştiricisi hedef temsilci parametresinin refness değiştiricisi ile eşleşen bir yöntem parametresini, uyuşmayan bir parametreye tercih edebilir. Bu nedenle, aşağıdaki örnek 12yazacaktır.

class C
{
    void M(I1 o, ref readonly int x) => System.Console.Write("1");
    void M(I2 o, ref int x) => System.Console.Write("2");
    void Run()
    {
        D1 m1 = this.M;
        D2 m2 = this.M; // currently ambiguous

        var i = 5;
        m1(null, in i);
        m2(null, ref i);
    }
    static void Main() => new C().Run();
}
interface I1 { }
interface I2 { }
class X : I1, I2 { }
delegate void D1(X s, ref readonly int x);
delegate void D2(X s, ref int x);

Tasarım toplantıları