Aracılığıyla paylaş


Kovaryan dönüşler

Not alın

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ında kaydedilir.

Ö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/49

Özet

covaryant dönüş türlerini destekle. Özellikle, bir yöntemin geçersiz kılınmasına; geçersiz kılınan yöntemin dönüş türünden daha türetilmiş bir dönüş türü bildirmesine, benzer şekilde bir salt okunur özelliğin geçersiz kılınmasına ve daha türetilmiş bir tür bildirmesine izin ver. Daha fazla türetilmiş türlerde görünen geçersiz kılma bildirimlerinin, en azından temel türlerindeki geçersiz kılmalarda görünen kadar belirli bir dönüş türü sağlaması gerekir. Yöntem veya özelliği çağıranlar, bir çağrıdan statik olarak daha hassas bir dönüş türü alır.

Motivasyon

Gerçekleştirilen geçersiz kılmaların, geçersiz kılınan metodla aynı türü geri döndürme zorunluluğuna bir geçici çözüm olarak, farklı metod adlarının oluşturulması sıkça rastlanan bir kodlama desenidir.

Bu, fabrika düzeninde yararlı olabilir. Örneğin, Roslyn kod tabanında şuna sahip olurduk.

class Compilation ...
{
    public virtual Compilation WithOptions(Options options)...
}
class CSharpCompilation : Compilation
{
    public override CSharpCompilation WithOptions(Options options)...
}

Ayrıntılı tasarım

Bu, C# dilinde kovaryant dönüş türleri için bir belirtimdir. Amacımız, bir yöntemin geçersiz kılınan yönteme göre daha türetilmiş bir dönüş türü döndürmesine izin vermek ve benzer şekilde, salt okunur bir özelliği geçersiz kılarak daha türetilmiş bir dönüş türü döndürmesine izin vermektir. Yöntemin veya özelliğin çağıranları bir çağrıdan statik olarak daha iyileştirilmiş dönüş türünü alır ve daha türetilmiş türlerde görünen geçersiz kılmalar, en azından temel türlerindeki geçersiz kılmalarda gösterilene özgü bir dönüş türü sağlamak için gerekli olacaktır.


Sınıf Yöntemini Geçersiz Kılma

Sınıf geçersiz kılma (§15.6.5) yöntemlerinde mevcut kısıtlama

  • Geçersiz kılma yöntemi ve geçersiz kılınan temel yöntem aynı dönüş türüne sahiptir.

olarak değiştirildi

  • Geçersiz kılma yönteminin, kimlik dönüşümü ile dönüştürülebilir bir dönüş türü olmalıdır veya eğer yöntem bir değer döndürüyorsa - başvuru döndürmesi değil - örtük başvuru dönüşümünün geçersiz kılınan temel yöntemin dönüş türüne uygulanması gerekir. §13.1.0.5'e bakın.

Bu listeye aşağıdaki ek gereksinimler eklenir:

  • Geçersiz kılma yönteminin dönüş türü, bir kimlik dönüşümü ile dönüştürülebilir olmalı veya (yöntem bir değer döndürüyor ve referans döndürmüyor ise, §13.1.0.5) geçersiz kılma yönteminin doğrudan veya dolaylı temel türlerinde bildirilen, geçersiz kılınan temel yöntemin her bir geçersiz kılmasının dönüş türüne örtük bir referans dönüşümü sağlamalıdır.
  • Geçersiz kılma yönteminin dönüş türü en az geçersiz kılma yöntemi kadar erişilebilir olmalıdır (Erişilebilirlik etki alanları - §7.5.3).

Bu kısıtlama, private sınıfındaki bir geçersiz kılma yönteminin private dönüş türüne sahip olmasına izin verir. Ancak, public dönüş türüne sahip olmak için public türünde bir public geçersiz kılma yöntemi gerektirir.

Sınıf Özelliği ve Dizin Oluşturucu Geçersiz Kılma

Sınıf geçersiz kılma (§15.7.6) özelliklerinde var olan kısıtlama

Geçersiz kılma özelliği bildirimi devralınan özellik ile tam olarak aynı erişilebilirlik değiştiricilerini ve adını belirtecektir ve geçersiz kılma türü ile devralınan özellikarasında bir kimlik dönüştürme olacaktır. Devralınan özelliğin yalnızca tek bir erişimcisi varsa (devralınan özellik salt okunur veya salt yazılırsa), üstüne yazılan özellik yalnızca bu erişimciyi içermelidir. Devralınan özellik her iki erişimciyi de içeriyorsa (devralınan özellik okuma-yazma ise), geçersiz kılma özelliği tek bir erişimci veya her iki erişimciyi de içerebilir.

olarak değiştirildi

Geçersiz kılma mülkü bildirimi, devralınan mülkle tam olarak aynı erişilebilirlik değiştiricilerini ve adını belirtecektir ve kimlik dönüştürmesi veya (devralınan mülk salt okunursa ve değer döndürmüşse - başvuru dönüşü§13.1.0.5) geçersiz kılma mülkünün türünden devralınan mülkün türüne örtük başvuru dönüştürmesi. Devralınan özelliğin yalnızca tek bir erişimcisi varsa (devralınan özellik salt okunur veya salt yazılırsa), üstüne yazılan özellik yalnızca bu erişimciyi içermelidir. Devralınan özellik her iki erişimciyi de içeriyorsa (devralınan özellik okuma-yazma ise), geçersiz kılma özelliği tek bir erişimci veya her iki erişimciyi de içerebilir. Geçersiz kılınan özelliğin türü, geçersiz kılan özellik kadar erişilebilir olmalıdır (Erişilebilirlik etki alanları - §7.5.3).


Aşağıdaki taslak belirtiminin geri kalanı, daha sonra dikkate alınması gereken arabirim yöntemlerinin kovaryant dönüşlerine ek bir uzantı önerir.

Arayüz Yöntemi, Özelliği ve Dizinleyici Geçersiz Kılma

C# 8.0'da DIM özelliği ile bir arabirimde izin verilen üye türlerine ek olarak, override üyelerine ve kovaryant dönüşlere destek ekleniyor. Bunlar, sınıflar için belirtilen override üyelerin kurallarına uyar ve aşağıdaki farkları içerir:

Sınıflarda aşağıdaki metin:

Geçersiz kılma bildirimiyle geçersiz kılınan temel yöntem, olarak bilinir. Msınıfında bildirilen bir geçersiz kılma yöntemi C için, geçirilen temel yöntem, C doğrudan temel sınıfıyla başlayarak C'nin her bir temel sınıfı incelenerek belirlenir ve her ardışık doğrudan temel sınıf bu incelemeye dahil edilir. Belirli bir temel sınıf türünde, tür bağımsız değişkenlerinin yerine konması sonrasında M ile aynı imzaya sahip en az bir erişilebilir yöntem bulunduğunda bu süreç tamamlanır.

arabirimler için ilgili belirtim verilmiştir:

Geçersiz kılma bildirimiyle geçersiz kılınan temel yöntem, olarak bilinir. Marabiriminde bildirilen geçersiz kılma metodu I için, yerine geçen üst metot, I'nin doğrudan veya dolaylı üst arabirimlerinin her biri incelenerek belirlenir. Aynı imzaya sahip erişilebilir bir metot bildiren arabirimler kümesi, tür parametreleri değiştirildiğinde M ile aynı imzaya sahip olacak şekilde toplanır. Bu arabirim kümesinde, bu kümedeki her tür için bir kimlik veya örtük başvuru dönüşümü olanen çok türetilmiş bir türü varsa ve o tür benzersiz bir yöntem bildirimi içeriyorsa, bu,geçersiz kılınan temel yöntemdir.

Benzer şekilde, overridesınıflar için belirtilen arabirimlerde özelliklerine ve dizin oluşturucularına izin veririz.

İsim Arama

Günümüzde, sınıf override bildirimlerinin varlığında ad araması, tanımlayıcının niteleyicisinin türünden başlayarak sınıf hiyerarşisindeki en türetilmiş override bildiriminden (veya niteleyici olmadığında this) elde edilen üye detaylarını uygulayarak ad aramasının sonucunu değiştirir. Örneğin, §12.6.2.2 İlgili parametreler belgesinde şunlar vardır

Sınıflarda tanımlanan sanal yöntemler ve dizin oluşturucular için parametre listesi, alıcının statik türüyle başlarken ve temel sınıflarında arama yaparken bulunan işlev üyesinin ilk bildiriminden veya geçersiz kılmasından seçilir.

buna ekliyoruz

Arabirimlerde tanımlanan sanal yöntemler ve dizin oluşturucular için parametre listesi, işlev üyesinin geçersiz kılma bildirimini içeren türler arasında en türetilmiş türde bulunan işlev üyesinin bildiriminden veya geçersiz kılmasından seçilir. Tür benzersiz değilse, bu derleme zamanı hatasıdır.

Bir özelliğin veya dizin oluşturucu erişiminin sonuç türü için, mevcut metin

  • I bir örnek özelliği tanımlarsa sonuç, E ilişkili örnek ifadesi ve özelliğin türü olan ilişkili bir tür ile özellik erişimidir. T bir sınıf türüyse, Tile başlayıp temel sınıflarında arama yaparken bulunan özelliğin ilk bildiriminden veya geçersiz kılmasından ilişkili tür seçilir.

ile zenginleştirildi

T bir arabirim türüyse, ilişkili tür, T'in en türevlenmiş hali veya doğrudan ya da dolaylı temel arabirimlerinden birinde bulunan özelliğin bildiriminden veya geçersiz kılmasından seçilir. Tür benzersiz değilse, bu derleme zamanı hatasıdır.

§12.8.12.3 Dizin Oluşturucu erişiminde de benzer bir değişiklik yapılması gerekiyor

§12.8.10 Çağırma ifadelerinde var olan metni genişletiyoruz

  • Aksi takdirde sonuç, yöntem veya temsilcinin dönüş türüne bağlı olan bir değerdir. Çağırma bir örnek yöntemine aitse ve alıcı Tbir sınıf türündeyse, ilişkili tür, T ile başlayıp temel sınıflarında arama yaparken bulunan yöntemin ilk bildiriminden veya geçersiz kılınmasından seçilir.

ile

Eğer çağırma bir nesne yöntemi ise ve alıcı arabirim tipi Tise, ilişkili tür, T ve onun doğrudan ve dolaylı temel arabirimleri arasından en çok türetilen arabirimde bulunan yöntemin bildiriminden veya geçersiz kılınmasından seçilir. Tür benzersiz değilse, bu derleme zamanı hatasıdır.

Örtük Arabirim Uygulamaları

Belirtimin bu bölümü

Arabirim eşleme amacıyla, bir sınıf üyesi A aşağıdaki durumlarda arabirim üyesi B eşleşir:

  • A ve B yöntemlerdir ve A ve B ad, tür ve resmi parametre listeleri aynıdır.
  • A ve B özelliklerdir, A ve B adı ve türü aynıdır ve AB ile aynı erişimcilere sahiptir (A açık arabirim üyesi uygulaması değilse ek erişimcilere izin verilir).
  • A ve B olaylardır ve A ve B adı ve türü aynıdır.
  • A ve B dizin oluşturuculardır, A ve B türü ve resmi parametre listeleri aynıdır ve AB ile aynı erişimcilere sahiptir (A açık bir arabirim üyesi uygulaması değilse ek erişimcilere izin verilir).

aşağıdaki gibi değiştirilir:

Arabirim eşleme amacıyla, bir sınıf üyesi A aşağıdaki durumlarda arabirim üyesi B eşleşir:

  • A ve B yöntemlerdir. A ve B'ün adları ve resmi parametre listeleri aynıdır. A dönüş türü, B'nın dönüş türüne olan örtük referans dönüşümü ile kimlik aracılığıyla B dönüş türüne dönüştürülebilir.
  • A ve B, özelliklerdir; A ve B'ün adları aynıdır; A, B ile aynı erişimcilere sahiptir (A, açık bir arabirim üyesi uygulaması değilse ek erişimcilere izin verilir); ve A türü, kimlik dönüştürmesi yoluyla veya eğer B salt okunur bir özellikse, A dönüş türüne örtülü bir başvuru dönüştürmesiyle uyarlanabilir.
  • A ve B olaylardır ve A ve B adı ve türü aynıdır.
  • A ve B dizin oluşturuculardır, A ve B resmi parametre listeleri aynıdır, AB ile aynı erişimcilere sahiptir (A açık bir arabirim üyesi uygulaması değilse ek erişimcilere izin verilir) ve A türü kimlik dönüştürme yoluyla B dönüş türüne dönüştürülebilir veya A salt okunur bir dizin oluşturucuysa örtük başvuru dönüştürmesi.

Bu, teknik olarak, aşağıdaki program bugün "C1.M" yazdırırken, önerilen revizyonda "C2.M" yazdıracağı için önemli bir değişikliktir.

using System;

interface I1 { object M(); }
class C1 : I1 { public object M() { return "C1.M"; } }
class C2 : C1, I1 { public new string M() { return "C2.M"; } }
class Program
{
    static void Main()
    {
        I1 i = new C2();
        Console.WriteLine(i.M());
    }
}

Önemli bu değişiklik nedeniyle, örtük uygulamalarda kovaryant dönüş türlerini desteklemeyebiliriz.

Arabirim Uygulama Kısıtlamaları

Açık bir arabirim uygulamasının, temel arabirimlerindeki herhangi bir geçersiz kılmada belirtilen dönüş türünden daha az türetilmiş olmayan bir dönüş türünü belirtmesi gerektiğine dair bir kurala ihtiyacımız olacaktır.

API Uyumluluğu etkileri

TBD

Açık Sorunlar

Belirtim, çağıranın daha ayrıntılı dönüş türünü nasıl elde ettiğini belirtmez. Muhtemelen bu, arayanların en fazla türetilmiş geçersiz kılmanın parametre tanımlarını alma yöntemine benzer bir şekilde yapılacaktır.


Aşağıdaki arabirimlere sahipsek:

interface I1 { I1 M(); }
interface I2 { I2 M(); }
interface I3: I1, I2 { override I3 M(); }

I3'de I1.M() ve I2.M() yöntemlerinin "birleştirildiğini" unutmayın. I3uygularken her ikisini de birlikte uygulamak gerekir.

Genellikle özgün yönteme başvurmak için açık bir uygulama gerekir. Soru şu ki, bir sınıfta

class C : I1, I2, I3
{
    C IN.M();
}

Bu ne anlama geliyor? N ne olmalıdır?

I1.M veya I2.M (her ikisini birden değil) uygulamaya izin vermemizi ve bunu her ikisinin de bir uygulaması olarak değerlendirmemizi öneriyorum.

Dezavantaj -ları

  • [ ] Her dil değişikliği kendi maliyetini karşılamalıdır.
  • [ ] Derin devralma hiyerarşileri söz konusu olduğunda bile performansın makul olduğundan emin olmamız gerekir
  • [ ] Çeviri stratejisi yapıtlarının, eski derleyicilerden yeni IL kullanırken bile dil semantiğini etkilemediğinden emin olmamız gerekir.

Alternatif

Dil kurallarını biraz gevşeterek kaynakta izin verebiliriz.

// Possible alternative. This was not implemented.
abstract class Cloneable
{
    public abstract Cloneable Clone();
}

class Digit : Cloneable
{
    public override Cloneable Clone()
    {
        return this.Clone();
    }

    public new Digit Clone() // Error: 'Digit' already defines a member called 'Clone' with the same parameter types
    {
        return this;
    }
}

Çözülmemiş sorular

  • [ ] Bu özelliği kullanmak için derlenmiş API'ler dilin eski sürümlerinde nasıl çalışacak?

Tasarım toplantıları