Birlikte değişken dönüşlerCovariant returns

ÖzetSummary

Birlikte değişken dönüş türlerini destekler.Support covariant return types. Özellikle, bir yöntemi geçersiz kılmanın, geçersiz kıldığı yöntemden daha fazla türetilmiş bir dönüş türü bildirmek ve benzer şekilde, salt okunurdur bir özelliğin daha türetilmiş bir tür bildirmek için geçersiz kılınmasına izin vermek için.Specifically, permit the override of a method to declare a more derived return type than the method it overrides, and similarly to permit the override of a read-only property to declare a more derived type. Daha türetilmiş türlerde görünen geçersiz kılma bildirimlerinin, en az bir dönüş türü, temel türlerinde geçersiz Kılmalarda görünen şekilde sağlanması gerekir.Override declarations appearing in more derived types would be required to provide a return type at least as specific as that appearing in overrides in its base types. Yöntem veya özelliğin çağıranları, bir çağrıdan daha fazla iyileştirilmiş dönüş türü statik olarak alır.Callers of the method or property would statically receive the more refined return type from an invocation.

MotivasyonMotivation

Bu, kod içinde farklı yöntem adlarının, geçersiz kılınan yöntemle aynı türü döndürmesi gereken dil kısıtlaması etrafında çalışmak üzere oluşturulması gereken yaygın bir modeldir.It is a common pattern in code that different method names have to be invented to work around the language constraint that overrides must return the same type as the overridden method.

Bu, fabrika düzeninde yararlı olacaktır.This would be useful in the factory pattern. Örneğin, Roslyn kod tabanındaFor example, in the Roslyn code base we would have

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

Ayrıntılı tasarımDetailed design

Bu, C# ' de birlikte değişken dönüş türleri için bir belirtimdir.This is a specification for covariant return types in C#. Bizim amacımız, bir yöntemin geçersiz kılınmasından daha fazla türetilmiş bir dönüş türü döndürmesini ve benzer şekilde, salt okunurdur bir özelliğin daha türetilmiş bir dönüş türü döndürmesini sağlamak için de izin vermaktır.Our intent is to permit the override of a method to return a more derived return type than the method it overrides, and similarly to permit the override of a read-only property to return a more derived return type. Yöntem veya özelliğin çağıranları, bir çağrıdan daha fazla artan dönüş türü statik olarak alınır ve daha fazla türetilmiş türde görünen geçersiz kılmalar, en azından, temel türlerinde geçersiz Kılmalarda görünen şekilde bir dönüş türü sağlamak için gerekli olacaktır.Callers of the method or property would statically receive the more refined return type from an invocation, and overrides appearing in more derived types would be required to provide a return type at least as specific as that appearing in overrides in its base types.


Class yöntemi geçersiz kılmaClass Method Override

Sınıf geçersiz kılma yöntemlerinde var olan kısıtlamaThe existing constraint on class override methods

  • Override yöntemi ve geçersiz kılınan taban yöntemi aynı dönüş türüne sahip.The override method and the overridden base method have the same return type.

değiştirme tarihiis modified to

  • Geçersiz kılma yöntemi, bir kimlik dönüştürmesi ile dönüştürülebilir bir dönüş türüne sahip olmalıdır veya (yöntemin bir değer Return- refreturn değeri varsa) örtük başvuru, geçersiz kılınan temel yöntemin dönüş türüne dönüştürülür.The override method must have a return type that is convertible by an identity conversion or (if the method has a value return - not a ref return) implicit reference conversion to the return type of the overridden base method.

Ve aşağıdaki ek gereksinimler bu listeye eklenir:And the following additional requirements are appended to that list:

  • Geçersiz kılma yöntemi, bir kimlik dönüştürmesi ile dönüştürülebilir bir dönüş türüne sahip olmalıdır veya geçersiz kılma yönteminin (doğrudan veya dolaylı) temel türünde belirtilen geçersiz kılınan temel yöntemin her geçersiz kılmasının dönüş türüneörtülü başvuru dönüştürmesi.The override method must have a return type that is convertible by an identity conversion or (if the method has a value return - not a ref return) implicit reference conversion to the return type of every override of the overridden base method that is declared in a (direct or indirect) base type of the override method.
  • Geçersiz kılma yönteminin dönüş türü en az geçersiz kılma yöntemi (erişilebilirlik etki alanları) olarak erişilebilir olmalıdır.The override method's return type must be at least as accessible as the override method (Accessibility domains).

Bu kısıtlama, bir sınıftaki geçersiz kılma yönteminin private bir dönüş türüne sahip olmasını sağlar private .This constraint permits an override method in a private class to have a private return type. Ancak public , bir public tür içinde dönüş türü olması için bir geçersiz kılma yöntemi gerektirir public .However it requires a public override method in a public type to have a public return type.

Sınıf özelliği ve Dizin Oluşturucu geçersiz kılmaClass Property and Indexer Override

Sınıf geçersiz kılma özelliklerindeki mevcut kısıtlamaThe existing constraint on class override properties

Geçersiz kılan özellik bildirimi, devralınan özellikle aynı erişilebilirlik değiştiricilerini ve adını belirtir ve geçersiz kılma türü ile devralınan özelliğin türü arasındabir kimlik dönüştürmesi olacaktır.An overriding property declaration shall specify the exact same accessibility modifiers and name as the inherited property, and there shall be an identity conversion between the type of the overriding and the inherited property. Devralınan özelliğin yalnızca tek bir erişimcisi varsa (yani devralınan özellik salt okunurdur veya salt yazılır ise), geçersiz kılma özelliği yalnızca o erişimciyi içerir.If the inherited property has only a single accessor (i.e., if the inherited property is read-only or write-only), the overriding property shall include only that accessor. Devralınan özellik her iki erişimcileri de içeriyorsa (yani, devralınan Özellik okuma-yazma ise), geçersiz kılma özelliği tek bir erişimci veya her iki erişimci içerebilir.If the inherited property includes both accessors (i.e., if the inherited property is read-write), the overriding property can include either a single accessor or both accessors.

değiştirme tarihiis modified to

Geçersiz kılma özelliği bildirimi, devralınan özellikle aynı erişilebilirlik değiştiricilerini ve adını belirtir ve bir kimlik dönüştürmesi veya (devralınan özellik salt okunurdur ve bir başvurudeğeri döndürür), geçersiz kılma özelliğinin türünden devralınan özelliğin türüne örtük başvuru dönüştürmesi olur.An overriding property declaration shall specify the exact same accessibility modifiers and name as the inherited property, and there shall be an identity conversion or (if the inherited property is read-only and has a value return - not a ref return) implicit reference conversion from the type of the overriding property to the type of the inherited property. Devralınan özelliğin yalnızca tek bir erişimcisi varsa (yani devralınan özellik salt okunurdur veya salt yazılır ise), geçersiz kılma özelliği yalnızca o erişimciyi içerir.If the inherited property has only a single accessor (i.e., if the inherited property is read-only or write-only), the overriding property shall include only that accessor. Devralınan özellik her iki erişimcileri de içeriyorsa (yani, devralınan Özellik okuma-yazma ise), geçersiz kılma özelliği tek bir erişimci veya her iki erişimci içerebilir.If the inherited property includes both accessors (i.e., if the inherited property is read-write), the overriding property can include either a single accessor or both accessors. Geçersiz kılan özelliğin türü, geçersiz kılma özelliği (erişilebilirlik etki alanları) olarak en az erişilebilir olmalıdır.The overriding property's type must be at least as accessible as the overriding property (Accessibility domains).


Aşağıdaki taslak belirtiminin geri kalanı, daha sonra değerlendirilmesi için arabirim yöntemlerinin covaryant dönüşüne yönelik daha fazla uzantı önerir.The remainder of the draft specification below proposes a further extension to covariant returns of interface methods to be considered later.

Arabirim yöntemi, özelliği ve Dizin Oluşturucu geçersiz kılmaInterface Method, Property, and Indexer Override

C# 8,0 ' de DIM özelliğinin eklenmesine sahip bir arabirimde izin verilen üye türlerine ekleme, covaryant dönüşleriyle birlikte, Üyeler için de daha fazla destek ekleyeceğiz override .Adding to the kinds of members that are permitted in an interface with the addition of the DIM feature in C# 8.0, we further add support for override members along with covariant returns. Bunlar override , aşağıdaki farklılıklar ile sınıflar için belirtilen üyelerin kurallarını izler:These follow the rules of override members as specified for classes, with the following differences:

Sınıflarda aşağıdaki metin:The following text in classes:

Geçersiz kılma bildirimi tarafından geçersiz kılınan yöntem, geçersiz kılınan temel yöntem olarak bilinir.The method overridden by an override declaration is known as the overridden base method. Bir sınıfta belirtilen geçersiz kılma yöntemi için M C , geçersiz kılınan taban yöntemi, C doğrudan temel sınıfı ile başlayıp her bir ardışık doğrudan taban sınıfına devam eden her bir temel sınıfı incelenerek belirlenir C ve belirli bir temel sınıf türüne kadar aynı imzaya sahip olan en az bir erişilebilir yöntem bulunur M .For an override method M declared in a class C, the overridden base method is determined by examining each base class of C, starting with the direct base class of C and continuing with each successive direct base class, until in a given base class type at least one accessible method is located which has the same signature as M after substitution of type arguments.

, arabirimler için karşılık gelen belirtim verilmiştir:is given the corresponding specification for interfaces:

Geçersiz kılma bildirimi tarafından geçersiz kılınan yöntem *geçersiz kılınan temel yöntem _ olarak bilinir.The method overridden by an override declaration is known as the *overridden base method _. Bir arabirimde bildirildiği bir geçersiz kılma yöntemi için M I , geçersiz kılınan taban yöntemi, I M tür bağımsız değişkenlerinin yerine koyduktan sonraki aynı imzaya sahip erişilebilir bir yöntemi bildiren bir erişilebilir yöntemi bildiren, her bir doğrudan veya dolaylı temel arabirimini inceleyerek belirlenir.For an override method M declared in an interface I, the overridden base method is determined by examining each direct or indirect base interface of I, collecting the set of interfaces declaring an accessible method which has the same signature as M after substitution of type arguments. Bu tür arabirimlerde, bu küme içindeki her türden bir kimlik veya örtük başvuru dönüştürmesi olduğu için _most türetilmiş bir tür * varsa ve bu tür benzersiz bir tür yöntem bildirimi içeriyorsa, bu, geçersiz kılınan temel yöntemdir.If this set of interfaces has a _most derived type*, to which there is an identity or implicit reference conversion from every type in this set, and that type contains a unique such method declaration, then that is the overridden base method.

Benzer şekilde, override 15.7.6 sanal, Sealed, override ve abstract erişimcileri içindeki sınıflar için belirtilen arabirimlerde Özellikler ve Dizin oluşturuculara izin veririz.We similarly permit override properties and indexers in interfaces as specified for classes in 15.7.6 Virtual, sealed, override, and abstract accessors.

Ad aramaName Lookup

Sınıf bildirimlerinde ad araması override Şu anda, override tanımlayıcı niteleyicisi türünden (veya niteleyicisi olmadığında) sınıf hiyerarşisindeki en çok türetilen bildirimden bulunan üye ayrıntılarını düzenleyerek ad arama sonucunu değiştirir this .Name lookup in the presence of class override declarations currently modify the result of name lookup by imposing on the found member details from the most derived override declaration in the class hierarchy starting from the type of the identifier's qualifier (or this when there is no qualifier). Örneğin, 12.6.2.2 karşılık gelen parametrelere sahip olduğumuzFor example, in 12.6.2.2 Corresponding parameters we have

Sınıflarda tanımlı sanal yöntemler ve Dizin oluşturucular için, parametre listesi ilk bildirimden alınır veya alıcının statik türüyle Başlarken bulunan işlev üyesinin geçersiz kılması ve temel sınıfları üzerinde arama yapılır.For virtual methods and indexers defined in classes, the parameter list is picked from the first declaration or override of the function member found when starting with the static type of the receiver, and searching through its base classes.

Şu şekilde ekleyeceğizto this we add

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ındaki en türetilmiş türde bulunan işlev üyesinin bildiriminden veya geçersiz kılınmasından çekilir.For virtual methods and indexers defined in interfaces, the parameter list is picked from the declaration or override of the function member found in the most derived type among those types containing the declaration of override of the function member. Böyle bir benzersiz tür yoksa, derleme zamanı hatasıdır.It is a compile-time error if no unique such type exists.

Bir özelliğin sonuç türü veya Dizin Oluşturucu erişimi için, varolan metinFor the result type of a property or indexer access, the existing text

  • Bir örnek özelliği tanımlarsa sonuç, ilişkili bir örnek ifadesi ve özelliğin türü olan ilişkili bir tür olan bir özellik erişimiydi.If I identifies an instance property, then the result is a property access with an associated instance expression of E and an associated type that is the type of the property. T bir sınıf türü ise, ilişkili tür ilk bildirimden çekilir veya T ile başlatıldığında bulunan özelliğin geçersiz kılınması ve temel sınıfları üzerinde arama yapılır.If T is a class type, the associated type is picked from the first declaration or override of the property found when starting with T, and searching through its base classes.

Şu şekilde genişlettilmişis augmented with

T bir arabirim türü ise, ilişkili tür bildirimden ya da doğrudan ya da dolaylı temel arabirimlerde bulunan özelliğin veya geçersiz kılınmasından çekilir.If T is an interface type, the associated type is picked from the declaration or override of the property found in the most derived of T or its direct or indirect base interfaces. Böyle bir benzersiz tür yoksa, derleme zamanı hatasıdır.It is a compile-time error if no unique such type exists.

12.7.7.3 Indexer erişiminde benzer bir değişiklik yapılmalıdırA similar change should be made in 12.7.7.3 Indexer access

12.7.6 çağırma ifadelerinde , varolan metni koruyorIn 12.7.6 Invocation expressions we augment the existing text

  • Aksi takdirde sonuç, yöntemin veya temsilcinin bir tür dönüş türüne sahip bir değerdir.Otherwise, the result is a value, with an associated type of the return type of the method or delegate. Çağırma bir örnek yöntemi ise ve alıcı T sınıf türünde ise, ilişkili tür ilk bildirimden çekilir veya T ile Başlarken ve temel sınıfları arasında arama yaparken bulunan yöntemin geçersiz kılınması.If the invocation is of an instance method, and the receiver is of a class type T, the associated type is picked from the first declaration or override of the method found when starting with T and searching through its base classes.

örneklerini şununla değiştirin:with

Çağırma bir örnek yöntemi ise ve alıcı T arabirim türünde ise, ilişkili tür, T ve doğrudan ve dolaylı temel arabirimleri arasından en türetilmiş arabirimde bulunan yöntemin bildiriminden veya geçersiz kılınmasından çekilir.If the invocation is of an instance method, and the receiver is of an interface type T, the associated type is picked from the declaration or override of the method found in the most derived interface from among T and its direct and indirect base interfaces. Böyle bir benzersiz tür yoksa, derleme zamanı hatasıdır.It is a compile-time error if no unique such type exists.

Örtük arabirim uygulamalarıImplicit Interface Implementations

Belirtimin bu bölümüThis section of the specification

Arabirim eşleme amaçları doğrultusunda, bir sınıf üyesi şu A durumlarda bir arabirim üyesiyle eşleşir B :For purposes of interface mapping, a class member A matches an interface member B when:

  • A ve B metodlardır ve ad, tür ve biçimsel parametre listeleri A B aynıdır.A and B are methods, and the name, type, and formal parameter lists of A and B are identical.
  • A , ve ' B nin adı ve türü aynıdır ve A B A aynı erişimcilere sahiptir B ( A açık bir arabirim üyesi uygulama değilse ek erişimcilere izin verilir).A and B are properties, the name and type of A and B are identical, and A has the same accessors as B (A is permitted to have additional accessors if it is not an explicit interface member implementation).
  • A ve B olayları ve adı ve türü A B özdeş.A and B are events, and the name and type of A and B are identical.
  • A ve B Dizin oluşturucular, tür ve biçimsel parametre listeleri ve aynıdır A B ve A aynı erişimcilere sahiptir B ( A Açık arabirim üyesi uygulama değilse ek erişimcilere izin verilir).A and B are indexers, the type and formal parameter lists of A and B are identical, and A has the same accessors as B (A is permitted to have additional accessors if it is not an explicit interface member implementation).

Şu şekilde değiştirilir:is modified as follows:

Arabirim eşleme amaçları doğrultusunda, bir sınıf üyesi şu A durumlarda bir arabirim üyesiyle eşleşir B :For purposes of interface mapping, a class member A matches an interface member B when:

  • A ve B metodlardır ve ' nin adı ve biçimsel parametre listeleri aynıdır ve dönüş türü, dönüş türüne dönüşsüz A B A B bir kimlik ile dönüş türüne dönüştürülebilir B .A and B are methods, and the name and formal parameter lists of A and B are identical, and the return type of A is convertible to the return type of B via an identity of implicit reference convertion to the return type of B.
  • A Ayrıca, B ve adı aynı A B olan ve A aynı erişimcilere sahiptir B ( A bir açık arabirim üye uygulamasının olmaması durumunda ek erişimcilere izin verilir) ve türü A B bir kimlik dönüştürmesi yoluyla dönüş türüne dönüştürülebilir veya bir A salt okunur özelliktir, örtük bir başvuru dönüştürmesi olur.A and B are properties, the name of A and B are identical, A has the same accessors as B (A is permitted to have additional accessors if it is not an explicit interface member implementation), and the type of A is convertible to the return type of B via an identity conversion or, if A is a readonly property, an implicit reference conversion.
  • A ve B olayları ve adı ve türü A B özdeş.A and B are events, and the name and type of A and B are identical.
  • A ve ' B de, biçimsel parametre listeleri A ve aynıdır, B A aynı erişimcilere sahiptir B (bir A Açık arabirim üyesi uygulama olmaması durumunda ek erişimcilere izin verilir) ve türü A B bir kimlik dönüştürmesi yoluyla dönüş türüne dönüştürülebilir veya bir A salt okunur dizin oluşturucu ise örtük bir başvuru dönüştürmesi olur.A and B are indexers, the formal parameter lists of A and B are identical, A has the same accessors as B (A is permitted to have additional accessors if it is not an explicit interface member implementation), and the type of A is convertible to the return type of B via an identity conversion or, if A is a readonly indexer, an implicit reference conversion.

Bu, teknik olarak önemli bir değişiklik olduğundan, aşağıdaki program "C1" yazdırır. D "Bugün" C2. D "önerilen düzeltme altında.This is technically a breaking change, as the program below prints "C1.M" today, but would print "C2.M" under the proposed revision.

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());
    }
}

Bu önemli değişiklik nedeniyle örtük uygulamalarda birlikte değişken dönüş türlerini desteklememeyi düşünmeyebilirsiniz.Due to this breaking change, we might consider not supporting covariant return types on implicit implementations.

Arabirim uygulamasındaki kısıtlamalarConstraints on Interface Implementation

Açık bir arabirim uygulamasının, temel arabirimlerinde herhangi bir geçersiz kılmada belirtilen dönüş türünden daha az türetilmiş olmayan bir dönüş türü bildirmesi gerektiğini belirten bir kuralla ihtiyacımız olacak.We will need a rule that an explicit interface implementation must declare a return type no less derived than the return type declared in any override in its base interfaces.

API uyumluluğu etkileriAPI Compatibility Implications

TBDTBD

Açık SorunlarOpen Issues

Belirtim, çağıranın daha fazla iyileştirilmiş dönüş türünü nasıl aldığından söylemez.The specification does not say how the caller gets the more refined return type. Çağıranların en fazla türetilen geçersiz kılma parametre belirtimlerini elde eden yönteme benzer şekilde yapılacak şekilde yapılır.Presumably that would be done in a way similar to the way that callers get the most derived override's parameter specifications.


Aşağıdaki arabirimler varsa:If we have the following interfaces:

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

I3' De, yöntemleri I1.M() ve I2.M() "birleştirilmiş" olduğunu unutmayın.Note that in I3, the methods I1.M() and I2.M() have been “merged”. Uygulamasını uygularken I3 , bunları birlikte uygulamak gereklidir.When implementing I3, it is necessary to implement them both together.

Genellikle, özgün yönteme başvurmak için açık bir uygulama gerekir.Generally, we require an explicit implementation to refer to the original method. Soru, bir sınıftaThe question is, in a class

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

Burada bunun anlamı nedir?What does that mean here? Ne olmalıdır ?What should N be?

I1.MYa da I2.M (her ikisi değil) uygulamasına izin verdiğimiz ve her ikisinin de bir uygulaması olarak değerlendirmem gerektiğini öneriyor.I suggest that we permit implementing either I1.M or I2.M (but not both), and treat that as an implementation of both.

BulunmaktadırDrawbacks

  • [] Her dil değişikliğinin kendisi için ödeme yapılmalıdır.[ ] Every language change must pay for itself.
  • [] Derin devralma hiyerarşileri durumunda bile performansın makul olduğundan emin olunması gerekir[ ] We should ensure that the performance is reasonable, even in the case of deep inheritance hierarchies
  • [] Eski derleyicilerden yeni Il kullanılırken bile, çeviri stratejisinin yapıtlarının dil semantiğini etkilemediğinden emin olunması gerekir.[ ] We should ensure that artifacts of the translation strategy do not affect language semantics, even when consuming new IL from old compilers.

AlternatiflerAlternatives

Kaynak olarak, dil kurallarını izin vermek için biraz daha rahat olabilirWe could relax the language rules slightly to allow, in source,

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ümlenmemiş sorularUnresolved questions

  • [] Bu özelliği kullanmak için derlenen API 'Ler, dilin eski sürümlerinde çalışır mı?[ ] How will APIs that have been compiled to use this feature work in older versions of the language?

Tasarım toplantılarıDesign meetings