Aracılığıyla paylaş


varsayılan arabirim yöntemleri

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, dil tasarım toplantısı (LDM) ile ilgilinotlarda kaydedilir.

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

Şampiyon konusu: https://github.com/dotnet/csharplang/issues/52

Özet

Somut uygulamalara sahip arabirimlerdeki yöntemler sanal uzantı yöntemleri için destek ekleyin. Böyle bir arabirimi uygulayan bir sınıf veya yapı, arabirim yöntemi için sınıf veya yapı tarafından uygulanan ya da temel sınıflarından veya arabirimlerinden devralınan tek bir en belirgin uygulamaya sahip olmalıdır. Sanal uzantı yöntemleri, bir API yazarının gelecek sürümlerde bir arabirime kaynak veya bu arabirimin mevcut uygulamalarıyla ikili uyumluluğu bozmadan yöntemler eklemesine olanak tanır.

Bunlar Java'nın "Varsayılan Yöntemler"benzerdir.

(Olası uygulama tekniğine bağlı olarak) bu özellik CLI/CLR'de ilgili desteği gerektirir. Bu özelliğin avantajlarından yararlanan programlar platformun önceki sürümlerinde çalıştırılamaz.

Motivasyon

Bu özelliğin temel motivasyonları şunlardır:

  • Varsayılan arabirim yöntemleri, bir API yazarının gelecek sürümlerde bir arabirime, bu arabirimin mevcut uygulamalarıyla kaynak veya ikili uyumluluğu bozmadan yöntemler eklemesini sağlar.
  • Bu özellik, C# uygulamasının benzer özellikleri destekleyen Android (Java) ve iOS (Swift)hedefleyen API'lerle birlikte çalışabilmesini sağlar.
  • Sonuç olarak, varsayılan arabirim uygulamalarının eklenmesi "nitelikler" dil özelliğinin (https://en.wikipedia.org/wiki/Trait_(computer_programming)) öğelerini sağlar. Özelliklerin güçlü bir programlama tekniği (http://scg.unibe.ch/archive/papers/Scha03aTraits.pdf) olduğu kanıtlanmıştır.

Ayrıntılı tasarım

Bir arayüzün söz dizimi izin verecek şekilde genişletilmiştir.

  • sabitleri, operatörleri, statik oluşturucuları ve iç içe türleri bildiren üye bildirimleri;
  • Bir yöntem, dizin oluşturucu, özellik veya olay erişimcisi için gövde (yani, "varsayılan" bir uygulama);
  • statik alanları, yöntemleri, özellikleri, dizin oluşturucuları ve olayları bildiren üye bildirimleri;
  • açık arabirim uygulama söz dizimini kullanan üye bildirimleri; ve
  • Açık erişim değiştiricileri (varsayılan erişim public).

Gövdeye sahip üyeler, kendi uygulamalarını sağlamayan sınıflar ve yapılar için arabirime yöntemin "varsayılan" bir uygulamasını sağlamasına olanak tanır.

Arabirimler örnek durumu içermeyebilir. Statik alanlara artık izin verilse de örnek alanlarına arabirimlerde izin verilmez. Örnek otomatik özellikleri, gizli bir alanı örtük olarak bildireceğinden arabirimlerde desteklenmez.

Statik ve özel metotlar, arabirimin genel API'sini uygulamak için kullanılan kodun daha iyi düzenlenmesine ve yapılandırılmasına olanak tanır.

Bir arabirimdeki yöntem geçersiz kılma, açık arabirim uygulaması söz dizimini kullanmalıdır.

variance_annotationile bildirilen tür parametresinin kapsamı içinde bir sınıf türü, yapı türü veya sabit liste türünü bildirmek bir hatadır. Örneğin, aşağıdaki C bildirimi bir hatadır.

interface IOuter<out T>
{
    class C { } // error: class declaration within the scope of variant type parameter 'T'
}

Arabirimlerdeki somut yöntemler

Bu özelliğin en basit biçimi, gövdeye sahip bir yöntem olan arabirimde somut bir yöntem bildirebilme özelliğidir.

interface IA
{
    void M() { WriteLine("IA.M"); }
}

Bu arabirimi uygulayan bir sınıfın somut yöntemini uygulaması gerekmez.

class C : IA { } // OK

IA i = new C();
i.M(); // prints "IA.M"

Sınıf IA.M içindeki C için son geçersiz kılma, Miçinde bildirilen somut yöntem IA'dir. Bir sınıfın arabirimlerinden üyeleri devralmadığını unutmayın; bu özellik tarafından değiştirilmez:

new C().M(); // error: class 'C' does not contain a member 'M'

Bir arabirimin örnek üyesi içinde, this kapsayan arabirimin türüne sahiptir.

Arabirimlerdeki değiştiriciler

Bir arayüzün söz dizimi, üyelerinde değiştiricilere izin vermek için esnek hale getirilmiştir. Şunlara izin verilir: private, protected, internal, public, virtual, abstract, sealed, static, externve partial.

Bildirimi gövde içeren bir arabirim üyesi, virtual veya sealed değiştiricisi kullanılmadığı sürece private üyesidir. virtual değiştiricisinin, aksi takdirde örtük olarak virtualolacak bir işlev üyesinde kullanılmasına izin verilebilir. Benzer şekilde, abstract, gövdeleri olmayan arabirim üyelerinde varsayılan olsa da, bu değiştirici açıkça belirtilebilir. Sanal olmayan bir üye sealed anahtar sözcüğü kullanılarak bildirilebilir.

Bir arabirimin private veya sealed işlev üyesinin gövdesi olmaması bir hatadır. private işlev üyesi sealeddeğiştiricisine sahip olamaz.

Erişim değiştiricileri, izin verilen her türlü üyenin arabirim üyelerinde kullanılabilir. Erişim düzeyi public varsayılandır, ancak açıkça verilebilir.

Açık Sorun:protected ve internalgibi erişim değiştiricilerinin tam anlamını ve hangi bildirimlerin bunları türetilmiş bir arabirimde geçersiz kılıp kılmadığını veya bir arabirimi uygulayan sınıfta bunları uygulayıp uygulamadığını belirtmemiz gerekir.

Arabirimler iç içe türler, yöntemler, dizin oluşturucular, özellikler, olaylar ve statik oluşturucular dahil olmak üzere static üyelerini bildirebilir. Tüm arabirim üyeleri için varsayılan erişim düzeyi public.

Arabirimler örnek oluşturucuları, yıkıcıları veya alanları bildirmeyebilir.

Kapalı Sorun: bir arabirimde işleç bildirimlerine izin verilsin mi? Büyük olasılıkla dönüştürme işleçleri değildir, peki ya diğerleri? Karar: Dönüştürme, eşitlik ve eşitsizlik işleçleri için dışında işleçlere izin verilir.

Kapalı Sorun: Üyeleri temel arabirimlerden gizleyen arabirim üyesi bildirimlerinde new izin verilmeli mi? Karar: Evet.

Kapalı Sorun: Şu anda bir arabirimde veya üyelerinde partial izin vermiyoruz. Bunun için ayrı bir teklif gerekir. Karar: Evet. https://github.com/dotnet/csharplang/blob/master/meetings/2018/LDM-2018-10-17.md#permit-partial-in-interface

Arabirimlerde açık uygulama

Açık uygulamalar, programcının derleyicinin veya çalışma zamanının kendi başına bulamayacağı bir arabirimde sanal üyenin en özgün uygulamasını sağlamasına olanak tanır. Bir uygulama bildiriminin, bildirimi arabirim adıyla niteleyerek belirli bir temel arabirim yöntemini açıkça izin verilir (bu durumda erişim değiştiricisine izin verilmez). Örtük uygulamalara izin verilmez.

interface IA
{
    void M() { WriteLine("IA.M"); }
}
interface IB : IA
{
    void IA.M() { WriteLine("IB.M"); } // Explicit implementation
}
interface IC : IA
{
    void M() { WriteLine("IC.M"); } // Creates a new M, unrelated to `IA.M`. Warning
}

Arabirimlerdeki açık uygulamalar sealedbildirilmeyebilir.

Bir arabirimdeki genel virtual işlev üyeleri, yalnızca türetilmiş bir arabirimde açıkça uygulanabilir. Bu, bildirimde adın, yöntemi ilk bildiren arabirim türüyle belirtilmesi ve bir erişim değiştirici kullanılmaması anlamına gelir. Uygulandığı yerde üyenin erişilebilir olması gerekir.

Yeniden Soyutlama

Arabirimde bildirilen bir sanal (somut) yöntem, türetilmiş bir arabirimde yeniden çekilebilir

interface IA
{
    void M() { WriteLine("IA.M"); }
}
interface IB : IA
{
    abstract void IA.M();
}
class C : IB { } // error: class 'C' does not implement 'IA.M'.

abstract değiştirici, IB.M'nin tekrar soyutlandığını belirtmek için IA.Mbildiriminde gereklidir.

Bu, bir yöntemin varsayılan uygulamasının uygun olmadığı ve sınıflar uygulanarak daha uygun bir uygulama sağlanması gereken türetilmiş arabirimlerde kullanışlıdır.

En özel uygulama kuralı

Tür veya doğrudan ve dolaylı arabirimlerinde görünen uygulamalar arasında her sanal üye için, her arabirim ve sınıfın en özel uygulamaya sahip olması gerekir. En özel uygulama, diğer tüm uygulamalardan daha özel olan benzersiz bir uygulamadır. Uygulama yoksa, üyenin kendisi en özel uygulama olarak kabul edilir.

Bir uygulama M1, başka bir uygulama 'ten daha M2 olarak kabul edilir, eğer M1T1türünde bildirilmişse, M2T2türünde bildirilmişse ve/veya.

  1. T1, doğrudan veya dolaylı arabirimleri arasında T2 içerir veya
  2. T2 bir arabirim türüdür ancak T1 bir arabirim türü değildir.

Mesela:

interface IA
{
    void M() { WriteLine("IA.M"); }
}
interface IB : IA
{
    void IA.M() { WriteLine("IB.M"); }
}
interface IC : IA
{
    void IA.M() { WriteLine("IC.M"); }
}
interface ID : IB, IC { } // compiles, but error when a class implements 'ID'
abstract class C : IB, IC { } // error: no most specific implementation for 'IA.M'
abstract class D : IA, IB, IC // ok
{
    public abstract void M();
}
public class E : ID { } // Error. No most specific implementation for 'IA.M'

En özel uygulama kuralı, çakışmanın (yani elmas devralmadan kaynaklanan bir belirsizlik) çakışmanın ortaya çıktığı noktada programcı tarafından açıkça çözülmesini sağlar.

Arabirimlerde açık yeniden soyutlamaları desteklediğimiz için bunu sınıflarda da yapabiliriz.

abstract class E : IA, IB, IC // ok
{
    abstract void IA.M();
}

kapalı sorun: sınıflarda açık arabirim soyut uygulamalarını desteklemeli miyiz? Karar YOK:

Buna ek olarak, bir sınıf bildiriminde bazı arabirim yönteminin en özel uygulaması bir arabirimde bildirilen soyut bir uygulamaysa bir hatadır. Bu, yeni terminoloji kullanılarak yeniden ifade edilen mevcut bir kuraldır.

interface IF
{
    void M();
}
abstract class F : IF { } // error: 'F' does not implement 'IF.M'

Bir arabirimde bildirilen bir sanal özelliğin bir arabirimde get erişimcisi için en belirli bir uygulamaya ve farklı bir arabirimdeki set erişimcisi için en özel uygulamaya sahip olması mümkündür. Bu, en özel uygulama kuralının ihlali olarak kabul edilir ve derleyici hatası oluşturur.

static ve private yöntemleri

Arabirimler artık yürütülebilir kod içerebileceğinden, ortak kodu özel ve statik yöntemlere soyutlama yararlı olur. Artık arabirimlerde bunlara izin veririz.

Kapalı sorunu: Özel yöntemleri desteklemeli miyiz? Statik yöntemleri desteklemeli miyiz? Karar: EVET

Açık sorun: Arabirim yöntemlerinin protected, internal veya başka bir erişime izin vermeli miyiz? Öyleyse, semantik nedir? Varsayılan olarak virtual mi? Öyleyse, bunları sanal olmayan hale getirmenin bir yolu var mı?

Kapalı sorunu: Statik yöntemleri destekliyorsak (statik) işleçleri desteklemeli miyiz? Karar: EVET

Temel arabirim çağrıları

Bu bölümdeki söz dizimi uygulanmadı. Bu, etkin bir teklif olmaya devam eder.

Varsayılan yönteme sahip bir arabirimden türetilen bir türdeki kod, bu arabirimin "temel" uygulamasını açıkça çağırabilir.

interface I0
{
   void M() { Console.WriteLine("I0"); }
}
interface I1 : I0
{
   override void M() { Console.WriteLine("I1"); }
}
interface I2 : I0
{
   override void M() { Console.WriteLine("I2"); }
}
interface I3 : I1, I2
{
   // an explicit override that invoke's a base interface's default method
   void I0.M() { I2.base.M(); }
}

Bir örnek (statik olmayan) yöntemin, base(Type).Mifadesini kullanarak adlandırıldığı takdirde, bir temel arabirimdeki erişilebilir örnek yöntemin uygulanmasını sanal olmayan bir şekilde çağırmasına izin verilir. Bu, elmas kalıtım nedeniyle sağlanması gereken bir geçersiz kılma, belirli bir ana uygulamaya delege edilerek çözümlendiğinde faydalıdır.

interface IA
{
    void M() { WriteLine("IA.M"); }
}
interface IB : IA
{
    override void IA.M() { WriteLine("IB.M"); }
}
interface IC : IA
{
    override void IA.M() { WriteLine("IC.M"); }
}

class D : IA, IB, IC
{
    void IA.M() { base(IB).M(); }
}

Bir virtual veya abstract üyesine sentaks base(Type).Mkullanılarak erişildiğinde, Type'ün için benzersiz M içermesi gereklidir.

Temel hükümlerin bağlanması

Arabirimler artık türler içeriyor. Bu türler temel ifadede temel arabirimler olarak kullanılabilir. Temel yan tümceyi bağlarken, bu türleri bağlamak için temel arabirim kümesini bilmemiz gerekebilir (örneğin, bu türlerde arama yapmak ve korumalı erişimi çözümlemek için). Bu nedenle bir arabirimin temel yan tümcesinin anlamı döngüsel olarak tanımlanır. Döngüyü bozmak için, sınıflar için zaten mevcut olan benzer bir kurala karşılık gelen yeni bir dil kuralı ekleriz.

Bir arabirimin interface_base anlamını belirlerken, temel arabirimlerin geçici olarak boş olduğu varsayılır. Sezgisel olarak bu, temel yan tümcenin anlamının özyinelemeli olarak kendisine bağımlı olmamasını sağlar.

Eskiden şu kurallara sahiptik:

"B sınıfı A sınıfından türetildiğinde, A'nın B'ye bağımlı olması derleme zamanı hatasıdır. Bir sınıf doğrudan doğrudan temel sınıfına (varsa) bağlıdır ve doğrudan, hemen iç içe yerleştirildiği sınıfı (varsa) bağlıdır. Bu tanım göz önüne alındığında, bir sınıfın bağımlı olduğu tam sınıf kümesi, doğrudan esnek ve geçişli kapanışı ilişkiye bağlıdır."

Bir arabirimin doğrudan veya dolaylı olarak kendisinden devralması derleme zamanı hatasıdır. Bir arabirimin temel arabirimleri, açık temel arabirimler ve bunların temel arabirimleridir. Başka bir deyişle, temel arabirim kümesi, açık temel arabirimlerin, bunların açık temel arabirimlerinin vb. tam geçişli kapanışıdır.

Bunları şu şekilde ayarlıyoruz:

B sınıfı A sınıfından türetildiğinde, A'nın B'ye bağımlı olması derleme zamanı hatasıdır. Bir sınıf , doğrudan temel sınıfı olan'e (varsa) bağlıdır ve , doğrudan iç içe yerleştirildiği türü içinde'ye (varsa) bağlıdır.

Arabirim IB, arabirim IA'yı genişlettiğinde, IA'nın IB'ye bağımlı olması derleme zamanı hatasıdır. Bir arabirim doğrudan temel arabirimlerine (varsa) ve doğrudan kapsandığı türe (varsa) bağlıdır.

Bu tanımlar göz önüne alındığında, bir türün bağımlı olduğu türlerinin tam kümesi, doğrudan ilişkisine bağımlılığın yansıtmalı ve geçişli kapanışıdır.

Mevcut programlar üzerindeki etkisi

Burada sunulan kuralların mevcut programların anlamı üzerinde hiçbir etkisi olmaması amaçlanmıştır.

Örnek 1:

interface IA
{
    void M();
}
class C: IA // Error: IA.M has no concrete most specific override in C
{
    public static void M() { } // method unrelated to 'IA.M' because static
}

Örnek 2:

interface IA
{
    void M();
}
class Base: IA
{
    void IA.M() { }
}
class Derived: Base, IA // OK, all interface members have a concrete most specific override
{
    private void M() { } // method unrelated to 'IA.M' because private
}

Aynı kurallar, varsayılan arabirim yöntemlerini içeren benzer duruma benzer sonuçlar verir:

interface IA
{
    void M() { }
}
class Derived: IA // OK, all interface members have a concrete most specific override
{
    private void M() { } // method unrelated to 'IA.M' because private
}

Sorun Kapatıldı: Bunun spesifikasyonun amaçlanan bir sonucu olduğunu onaylayın. Karar: EVET

Çalışma zamanı metod çözümü

Kapalı Sorun: Belirtim, arabirim varsayılan yöntemleri karşısında çalışma zamanı yöntemi çözümleme algoritmasını açıklamalıdır. Semantiğin dilin anlam bilgisiyle tutarlı olduğundan emin olmamız gerekir; örneğin, hangi bildirilen yöntemlerin bir internal yöntemini geçersiz kıldığı veya uyguladığı ya da uygulamadığını belirtmek gibi.

CLR destek API'si

Derleyicilerin bu özelliği destekleyen bir çalışma zamanı için ne zaman derleme yaptıklarını algılaması için, bu tür çalışma zamanlarına yönelik kitaplıklar, https://github.com/dotnet/corefx/issues/17116'de açıklanan API aracılığıyla bu gerçeği tanıtacak şekilde değiştirilir. Ekliyoruz

namespace System.Runtime.CompilerServices
{
    public static class RuntimeFeature
    {
        // Presence of the field indicates runtime support
        public const string DefaultInterfaceImplementation = nameof(DefaultInterfaceImplementation);
    }
}

Sorun açma: CLR özelliği için en iyi ad bu mu? CLR özelliği yalnızca bundan çok daha fazlasını yapar (ör. koruma kısıtlamalarını gevşetir, arabirimlerde geçersiz kılmaları destekler vb.). Belki de "arabirimlerde somut yöntemler" veya "özellikler" gibi bir şey olarak adlandırılmalıdır?

Belirtilecek diğer alanlar

  • [ ] Var olan arabirimlere varsayılan arabirim yöntemleri ve geçersiz kılmalar eklemenin neden olduğu kaynak ve ikili uyumluluk etkilerinin türlerinin kataloglanması yararlı olacaktır.

Dezavantaj -ları

Bu teklif, CLR belirtiminde eşgüdümlü bir güncelleştirme gerektirir (arabirimlerdeki somut yöntemleri ve yöntem çözümlemesini desteklemek için). Bu nedenle oldukça pahalı ve CLR değişiklikleri gerektireceğini tahmin ettiğimiz diğer özelliklerle birleştirmek buna değer olabilir.

Alternatif

Hiç kimse.

Çözülmemiş sorular

  • Yukarıda, teklif boyunca açık sorular belirtilmiştir.
  • Ayrıca açık soruların listesi için bkz. https://github.com/dotnet/csharplang/issues/406.
  • Ayrıntılı belirtim, çağrılacak kesin yöntemi seçmek için çalışma zamanında kullanılan çözümleme mekanizmasını açıklamalıdır.
  • Yeni derleyiciler tarafından üretilen ve eski derleyiciler tarafından tüketilen meta verilerin etkileşiminin ayrıntılı bir şekilde üzerinde çalışılması gerekir. Örneğin, kullandığımız meta veri gösteriminin, eski bir derleyici tarafından derlendiğinde bu arabirimi uygulayan mevcut bir sınıfı bozmak için arabirimde varsayılan bir uygulamanın eklenmesine neden olmadığından emin olmamız gerekir. Bu, kullanabileceğimiz meta veri gösterimini etkileyebilir.
  • Tasarım, diğer diller ve diğer diller için mevcut derleyicilerle birlikte çalışabilirliği dikkate almalıdır.

Çözümlenen Sorular

Soyut Geçersiz Kılma

Önceki taslak belirtimi, devralınan bir yöntemi "yeniden soyutlama" özelliğini içeriyordu.

interface IA
{
    void M();
}
interface IB : IA
{
    override void M() { }
}
interface IC : IB
{
    override void M(); // make it abstract again
}

Notlarım, 2017-03-20 tarihli olanlar, buna izin vermemeye karar verdiğimizi gösteriyor. Ancak, bunun için en az iki kullanım örneği vardır:

  1. Bu özelliğin bazı kullanıcılarının birlikte çalışabilmeyi umduğu Java API'leri bu tesise bağlıdır.
  2. özelliklerle programlama bundan yarar sağlar. Reabstraction, "traits" dil özelliğinin (https://en.wikipedia.org/wiki/Trait_(computer_programming)) unsurlarından biridir. Sınıflarda aşağıdakilere izin verilir:
public abstract class Base
{
    public abstract void M();
}
public abstract class A : Base
{
    public override void M() { }
}
public abstract class B : A
{
    public override abstract void M(); // reabstract Base.M
}

Ne yazık ki bu kod, izin verilmediği sürece bir dizi arabirim (özellik) olarak yeniden düzenlenemez. Jared'ın açgözlülük ilkesi gereğince,izin verilmelidir.

Kapalı konu: Yeniden soyutlamaya izin verilsin mi? [EVET] Notlarım yanlıştı. LDM notları, bir arabirimde yeniden soyutlamaya izin verir. Sınıfta değil.

Sanal Değiştirici ve Korumalı Değiştirici karşılaştırması

Aleksey Tsingauz:

Bazılarına izin vermemek için bir neden olmadığı sürece arabirim üyelerinde açıkça belirtilen değiştiricilere izin verme kararı aldık. Bu, sanal değiştirici ile ilgili ilginç bir soru getiriyor. Varsayılan uygulamaya sahip üyeler için gerekli mi olmalıdır?

Şöyle diyebiliriz:

  • uygulama yoksa ve ne sanal ne de korumalı belirtildiyse, üyenin soyut olduğunu varsayarız.
  • eğer bir uygulanma varsa ve ne soyut ne de mühürlü belirtilmemişse, üyenin sanal olduğunu varsayarız.
  • "Mühürlü değiştirici, bir yöntemi ne sanal ne de soyut yapmak için gereklidir."

Alternatif olarak, sanal bir üye için sanal değiştiricinin gerekli olduğunu söyleyebiliriz. Örneğin, uygulaması açıkça sanal değiştirici ile işaretlenmemiş bir üye varsa, bu sanal veya soyut değildir. Bu yaklaşım, bir yöntem bir sınıftan arabirime taşındığında daha iyi bir deneyim sağlayabilir:

  • Soyut bir yöntem daima soyut kalır.
  • sanal bir yöntem sanal kalır.
  • değiştiricisi olmayan bir yöntem ne sanal ne de soyut kalır.
  • sealed değiştirici geçersiz kılma yöntemi olmayan bir metoda uygulanamaz.

Ne düşünüyorsun?

Kapalı Sorun: Somut bir yöntem (uygulamalı) örtük olarak virtualolmalıdır? [EVET]

Kararları: LDM 2017-04-05'te Alındı.

  1. sanal olmayanlar açıkça sealed veya privatearacılığıyla ifade edilmelidir.
  2. sealed, gövdeleri sanal olmayan arabirim örneği nesne üyeleri yapmak için kullanılan anahtar sözcüktür.
  3. Arabirimlerdeki tüm değiştiricilere izin vermek istiyoruz
  4. İç içe türler de dahil olmak üzere arabirim üyeleri için varsayılan erişilebilirlik geneldir
  5. arabirimlerdeki özel fonksiyon üyeleri kendiliğinden mühürlenmiştir ve sealed üzerlerinde kullanılamaz.
  6. Arabirimlerdeki özel sınıflara izin verilir ve mühürlenebilir, bu mühürlenmiş kelimesinin sınıf bağlamındaki anlamıdır.
  7. Eksik bir teklif olmadıkça, arabirimlerde veya üyelerinde kısmi uygulamaya hâlâ izin verilmez.

İkili Uyumluluk 1

Bir kitaplık varsayılan bir uygulama sağladığında

interface I1
{
    void M() { Impl1 }
}
interface I2 : I1
{
}
class C : I2
{
}

I1.M'da C uygulamasının I1.Molduğunu anlıyoruz. I2 içeren derleme aşağıdaki gibi değiştirilir ve yeniden derlenirse ne olur?

interface I2 : I1
{
    override void M() { Impl2 }
}

ancak C yeniden derlenmez. Program çalıştırıldığında ne olur? (C as I1).M() çağırma

  1. I1.M çalıştırır
  2. I2.M çalıştırır
  3. Bir tür çalışma zamanı hatası oluşturur

Karar: 2017-04-11: Çalışma zamanı esnasında açıkça en belirgin geçersiz kılma olan I2.M'i çalıştırır.

Etkinlik erişimcileri (kapalı)

Kapalı Sorun: Bir olay "parça düzeyinde" geçersiz kılınabilir mi?

Şu durumu göz önünde bulundurun:

public interface I1
{
    event T e1;
}
public interface I2 : I1
{
    override event T
    {
        add { }
        // error: "remove" accessor missing
    }
}

"Bir olay bildiriminin, tıpkı bir sınıftaki gibi, yalnızca bir erişimci kullanımına izin verilmediğinden, olayın bu 'kısmi' uygulamasına izin verilmez; her iki erişimci de sağlanmalıdır (ya da hiçbiri sağlanmamalıdır)." Sözdiziminde gövdesi olmayan bir soyut kaldırma erişimcisine izin vererek de aynı şeyi gerçekleştirebilirsiniz.

public interface I1
{
    event T e1;
}
public interface I2 : I1
{
    override event T
    {
        add { }
        remove; // implicitly abstract
    }
}

Bunun yeni (önerilen) bir söz dizimi olduğunu unutmayın. Mevcut gramerde olay erişimcileri zorunlu bir gövdeye sahiptir.

Kapalı Sorun: Bir olay erişimcisi, arabirimlerdeki ve özellik erişimcilerindeki yöntemlerin bir vücudun atlanmasıyla (örtük olarak) soyutlama yöntemine benzer şekilde, bir gövdenin atlanmasıyla (örtük olarak) soyutlanabilir mi?

Karar: (2017-04-18) Hayır, olay bildirimleri için ya her iki somut erişimci ya da hiçbiri gereklidir.

Bir Sınıfta Yeniden Soyutlama (kapalı)

Sorun Kapandı: Buna izin verildiğini onaylamamız gerekir (aksi halde varsayılan uygulama eklemek uyumsuz değişiklik olabilir):

interface I1
{
    void M() { }
}
abstract class C : I1
{
    public abstract void M(); // implement I1.M with an abstract method in C
}

Karar: (2017-04-18) Evet, arabirim üyesi bildirimine gövde ekleme C'yi kesmemelidir.

Mühürlü Geçersiz Kılma (etkin değil)

Önceki soru, sealed değiştiricisinin arabirimdeki bir override üzerine uygulanabileceğini örtük olarak varsayar. Bu, taslak belirtimini çeliştirir. Geçersiz kılma işleminin mühürlenmesine izin vermek istiyor muyuz? Sızdırmazlık kaynağı ve ikili uyumluluk etkileri dikkate alınmalıdır.

Kapalı Sorun: Geçersiz kılmanın mühürlenmesine izin verelim mi?

Karar: (2017-04-18) Arabirimlerdeki aşırı yüklemelere sealed müsaade etmeyelim. Arabirim üyelerinde sealed tek kullanımı, onları ilk bildirimlerinde sanal olmayan hale getirmektir.

Elmas devralma ve sınıflar (kapalı)

Öneri taslağı, elmas devralma senaryolarında sınıf geçersiz kılmalarını, arabirim geçersiz kılmalarına tercih eder.

Her arabirim ve sınıfın, türü veya doğrudan ve dolaylı arabirimlerinde görünen geçersiz kılmalar arasında her arabirim yöntemi için en bir geçersiz kılma olması gerekir. En spesifik geçersiz kılma, diğer tüm geçersiz kılmalardan daha spesifik olan benzersiz bir geçersiz kılmadır. Geçersiz kılma yoksa, yöntemin kendisi en özel geçersiz kılma olarak kabul edilir.

Bir geçersiz kılma M1, M2türünde bildirilirse, M1T1türünde bildirilirse, başka bir geçersiz kılma M2T2 kabul edilir.

  1. T1, doğrudan veya dolaylı arabirimleri arasında T2 içerir veya
  2. T2 bir arabirim türüdür ancak T1 bir arabirim türü değildir.

Senaryo şudur:

interface IA
{
    void M();
}
interface IB : IA
{
    override void M() { WriteLine("IB"); }
}
class Base : IA
{
    void IA.M() { WriteLine("Base"); }
}
class Derived : Base, IB // allowed?
{
    static void Main()
    {
        IA a = new Derived();
        a.M();           // what does it do?
    }
}

Bu davranışı onaylamamız (veya başka bir şekilde karar vermemiz) gerekir

Kapalı Sorun: Karma sınıflar ve arabirimler için geçerli olan en özel geçersiz kılma için yukarıdaki taslak belirtimini onaylayın (bir sınıf bir arabirime göre önceliklidir). Bkz. https://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-04-19.md#diamonds-with-classes.

Arabirim yöntemleri ve yapılar (kapalı)

Varsayılan arabirim yöntemleri ve yapılar arasında bazı talihsiz etkileşimler vardır.

interface IA
{
    public void M() { }
}
struct S : IA
{
}

Arabirim üyelerinin devralınmadığını unutmayın:

var s = default(S);
s.M(); // error: 'S' does not contain a member 'M'

Sonuç olarak, istemcinin arabirim yöntemlerini çağırmak için yapıyı kutulaması gerekir

IA s = default(S); // an S, boxed
s.M(); // ok

Bu şekilde boks, bir struct türünün temel avantajlarını yener. Ayrıca, herhangi bir mutasyon yönteminin belirgin bir etkisi olmayacaktır, çünkü yapının kutulu kopya üzerinde çalışırlar:

interface IB
{
    public void Increment() { P += 1; }
    public int P { get; set; }
}
struct T : IB
{
    public int P { get; set; } // auto-property
}

T t = default(T);
Console.WriteLine(t.P); // prints 0
(t as IB).Increment();
Console.WriteLine(t.P); // prints 0

Kapalı Sorun: Bu konuda ne yapabiliriz:

  1. Bir struct'nin varsayılan bir uygulamayı devralmasını yasakla. Tüm arabirim yöntemleri bir structiçinde soyut olarak ele alınmalıdır. Daha sonra nasıl daha iyi çalışabileceğine karar vermek için zaman ayırabiliriz.
  2. Kutulamadan kaçınacak bir kod oluşturma stratejisi geliştirin. IB.Incrementgibi bir yöntemin içinde this türü, IBkısıtlanmış bir tür parametresine benzer olabilir. Bununla birlikte, çağıranın kısıtlanmaması için, soyut olmayan yöntemler arabirimlerden miras alınır. Bu, derleyiciyi artırabilir ve CLR uygulamasının çalışması önemli ölçüde artabilir.
  3. O konuda endişelenmeyin ve onu siğil olarak bırakın.
  4. Başka fikirler mi?

Karar: Bu konuda endişelenmeyin ve bunu bir siğil olarak bırakın. Bkz. https://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-04-19.md#structs-and-default-implementations.

Temel arabirim çağrıları (kapalı)

Bu karar C# 8'de uygulanmadı. base(Interface).M() söz dizimi uygulanmaz.

Taslak belirtimi, Java' dan esinlenen temel arabirim çağrıları için bir söz dizimi önerir: Interface.base.M(). En azından ilk prototip için bir söz dizimi seçmemiz gerekir. En sevdiğim base<Interface>.M().

Kapalı Sorun: Temel üye çağrısının söz dizimi nedir?

Karar: Söz dizimi base(Interface).M(). Bkz. https://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-04-19.md#base-invocation. Adlı arabirimin bir temel arabirim olması gerekir, ancak doğrudan temel arabirim olması gerekmez.

Açma Sorunu: Sınıf üyelerinde temel arabirim çağrılarına izin verilsin mi?

Karar: Evet. https://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-04-19.md#base-invocation

Ortak olmayan arabirim üyelerini geçersiz kılma (kapalı)

Bir arabirimde, temel arabirimlerden kamusal olmayan üyeler override değiştiricisi kullanılarak geçersiz kılınır. Üyeyi içeren arabirimi adıyla belirten "açık" bir override olduğunda, erişim değiştirici atlanır.

Kapalı Sorun: Arabirimi adlandırmayan "örtük" bir geçersiz kılmaysa, erişim değiştiricinin eşleşmesi gerekir mi?

Karar: Yalnızca kamu üyeleri otomatik olarak geçersiz kılınabilir ve erişim uyumlu olmalıdır. Bkz. https://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-04-18.md#dim-implementing-a-non-public-interface-member-not-in-list.

Açık Sorun: Erişim değiştirici gerekli mi, isteğe bağlı mı yoksa override void IB.M() {}gibi belirgin bir geçersiz kılmada atlanıyor mu?

Açık Sorun:override gerekli mi, isteğe bağlı mı yoksa void IB.M() {}gibi açık bir geçersiz kılmada atlanıyor mu?

Bir sınıfa genel olmayan bir arabirim üyesi nasıl uygulanır? Belki de açıkça yapılmalıdır?

interface IA
{
    internal void MI();
    protected void MP();
}
class C : IA
{
    // are these implementations?  Decision: NO
    internal void MI() {}
    protected void MP() {}
}

Kapalı Sorun: Bir sınıfta genel olmayan arabirim üyesi nasıl uygulanır?

Karar: Yalnızca genel olmayan arabirim üyelerini açıkça uygulayabilirsiniz. Bkz. https://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-04-18.md#dim-implementing-a-non-public-interface-member-not-in-list.

Karar: Arabirim üyelerinde override anahtar sözcüğüne izin verilmez. https://github.com/dotnet/csharplang/blob/master/meetings/2018/LDM-2018-10-17.md#does-an-override-in-an-interface-introduce-a-new-member

İkili Uyumluluk 2 (kapalı)

Her türün ayrı bir derlemede bulunduğu aşağıdaki kodu göz önünde bulundurun

interface I1
{
    void M() { Impl1 }
}
interface I2 : I1
{
    override void M() { Impl2 }
}
interface I3 : I1
{
}
class C : I2, I3
{
}

I1.M'da C uygulamasının I2.Molduğunu anlıyoruz. I3 içeren derleme aşağıdaki gibi değiştirilir ve yeniden derlenirse ne olur?

interface I3 : I1
{
    override void M() { Impl3 }
}

ancak C yeniden derlenmez. Program çalıştırıldığında ne olur? (C as I1).M() çağırma

  1. I1.M çalıştırır
  2. I2.M çalıştırır
  3. I3.M çalıştırır
  4. 2 veya 3, belirleyici
  5. Bir tür çalışma zamanı istisnası fırlatır

Karar: Özel durum oluşturma (5). Bkz. https://github.com/dotnet/csharplang/blob/master/meetings/2018/LDM-2018-10-17.md#issues-in-default-interface-methods.

Arabirimde partial izni tanınsın mı? (kapalı)

Arabirimlerin soyut sınıfların kullanım şekline benzer şekilde kullanılabileceğini göz önünde bulundurarak, bunları partialbildirmek yararlı olabilir. Bu özellikle jeneratörler karşısında yararlı olacaktır.

Teklifi: Arabirimlerin ve arabirim üyelerinin partialbildirilmeyebileceği dil kısıtlamasını kaldırın.

Karar: Evet. Bkz. https://github.com/dotnet/csharplang/blob/master/meetings/2018/LDM-2018-10-17.md#permit-partial-in-interface.

Arabirimde Main? (kapalı)

Açık Sorun: Bir arabirimdeki static Main yöntemi programın giriş noktası olmaya aday mı?

Karar: Evet. Bkz. https://github.com/dotnet/csharplang/blob/master/meetings/2018/LDM-2018-10-17.md#main-in-an-interface.

Genel sanal olmayan yöntemleri destekleme amacını onaylama (kapalı)

Bir arabirimde sanal olmayan genel yöntemlere izin verme kararımızı onaylayabilir (veya tersine çevirebilir miyiz?

interface IA
{
    public sealed void M() { }
}

Semi-Closed Sorun: (2017-04-18) Yararlı olacağını düşünüyoruz, ancak buna geri döneceğiz. Bu bir zihinsel model engelidir.

Karar: Evet. https://github.com/dotnet/csharplang/blob/master/meetings/2018/LDM-2018-10-17.md#confirm-that-we-support-public-non-virtual-methods.

Arabirimdeki bir override yeni bir üyeyi tanıtıyor mu? (kapalı)

Geçersiz kılma bildiriminin yeni üye getirip getirmediğini gözlemlemenin birkaç yolu vardır.

interface IA
{
    void M(int x) { }
}
interface IB : IA
{
    override void M(int y) { } // 'override' not permitted
}
interface IC : IB
{
    static void M2()
    {
        M(y: 3); // permitted? Decision: No.
    }
    override void IB.M(int z) { } // permitted? What does it override? Decision: No.
}

Açık Sorun: Arabirimdeki geçersiz kılma bildirimi yeni bir üye tanımlar mı? (kapalı)

Bir sınıfta geçersiz kılma yöntemi bazı anlamda "görünür" olur. Örneğin, parametrelerinin adları geçersiz kılınan yöntemdeki parametrelerin adlarından önceliklidir. Her zaman en özel bir geçersiz kılma olduğundan, arabirimlerde bu davranışı yinelemek mümkün olabilir. Ama bu davranışı yinelemek istiyor musunuz?

Ayrıca, bir geçersiz kılma metodunu "geçersiz kılmak" da mümkün mü? [Tartışmalı]

Karar: Arabirim üyelerinde override anahtar sözcüğüne izin verilmez. https://github.com/dotnet/csharplang/blob/master/meetings/2018/LDM-2018-10-17.md#does-an-override-in-an-interface-introduce-a-new-member.

Özel erişimciye sahip özellikler (kapalı)

Özel üyelerin sanal olmadığını ve sanal ve özel birleşimine izin verilmediğini söylüyoruz. Peki ya özel erişimcisi olan bir mülk?

interface IA
{
    public virtual int P
    {
        get => 3;
        private set { }
    }
}

Buna izin var mı? set erişim aracı burada virtual mi değil mi? Erişilebilir olduğu yerde geçersiz kılınabilir mi? Aşağıdakiler yalnızca get erişimcisini dolaylı olarak uygular mı?

class C : IA
{
    public int P
    {
        get => 4;
        set { }
    }
}

IA.P.set sanal olmadığı ve erişilebilir olmadığı için aşağıdakiler büyük olasılıkla bir hata mıdır?

class C : IA
{
    int IA.P
    {
        get => 4;
        set { } // Decision: Not valid
    }
}

Karar: İlk örnek geçerli görünürken, son örnek geçerli değildir. Bu, C# dilinde nasıl çalıştığına benzer şekilde çözümlenir. https://github.com/dotnet/csharplang/blob/master/meetings/2018/LDM-2018-10-17.md#properties-with-a-private-accessor

Temel Arabirim Çağrıları, 2. tur (kapalı)

Bu, C# 8'de uygulanmadı.

Temel çağrıları işlemeye yönelik önceki "çözümlememiz" aslında yeterli ifade sağlamaz. C# ve CLR'de Java'dan farklı olarak hem yöntem bildirimini içeren arabirimi hem de çağırmak istediğiniz uygulamanın konumunu belirtmeniz gerektiği ortaya çıktı.

Arabirimlerdeki temel çağrılar için aşağıdaki söz dizimini öneriyorum. Ona aşık değilim, ancak herhangi bir söz diziminin ifade edebilmesi gerekenleri gösterir:

interface I1 { void M(); }
interface I2 { void M(); }
interface I3 : I1, I2 { void I1.M() { } void I2.M() { } }
interface I4 : I1, I2 { void I1.M() { } void I2.M() { } }
interface I5 : I3, I4
{
    void I1.M()
    {
        base<I3>(I1).M(); // calls I3's implementation of I1.M
        base<I4>(I1).M(); // calls I4's implementation of I1.M
    }
    void I2.M()
    {
        base<I3>(I2).M(); // calls I3's implementation of I2.M
        base<I4>(I2).M(); // calls I4's implementation of I2.M
    }
}

Belirsizlik yoksa, daha basit yazabilirsiniz

interface I1 { void M(); }
interface I3 : I1 { void I1.M() { } }
interface I4 : I1 { void I1.M() { } }
interface I5 : I3, I4
{
    void I1.M()
    {
        base<I3>.M(); // calls I3's implementation of I1.M
        base<I4>.M(); // calls I4's implementation of I1.M
    }
}

Veya

interface I1 { void M(); }
interface I2 { void M(); }
interface I3 : I1, I2 { void I1.M() { } void I2.M() { } }
interface I5 : I3
{
    void I1.M()
    {
        base(I1).M(); // calls I3's implementation of I1.M
    }
    void I2.M()
    {
        base(I2).M(); // calls I3's implementation of I2.M
    }
}

Veya

interface I1 { void M(); }
interface I3 : I1 { void I1.M() { } }
interface I5 : I3
{
    void I1.M()
    {
        base.M(); // calls I3's implementation of I1.M
    }
}

Karar: base(N.I1<T>).M(s)kararlaştırıldı, bir çağrı bağlamamız varsa daha sonra burada sorun olabileceğini kabul ettik. https://github.com/dotnet/csharplang/blob/master/meetings/2018/LDM-2018-11-14.md#default-interface-implementations

Struct varsayılan yöntemi uygulamıyor mu uyarısı? (kapalı)

@vancem, bir değer türü bildirimi bir arabirim yöntemini geçersiz kılamazsa, bu yöntemin bir uygulamasını bir arabirimden devralsa bile ciddi bir şekilde uyarı üretmeyi düşünmemiz gerektiğini onaylar. Çünkü kutulamaya neden olur ve kısıtlanmış çağrıları baltalar.

Karar: Bu, çözümleyici için daha uygun bir şey gibi görünüyor. Ayrıca, varsayılan arabirim yöntemi hiçbir zaman çağrılmasa bile tetiklendiğinden ve hiçbir boks gerçekleşmeyeceğinden bu uyarı gürültülü olabilir gibi görünüyor. https://github.com/dotnet/csharplang/blob/master/meetings/2018/LDM-2018-10-17.md#warning-for-struct-not-implementing-default-method

Arabirim statik oluşturucuları (kapalı)

Arabirim statik oluşturucuları ne zaman çalıştırılır? Geçerli CLI taslağı, ilk statik yönteme veya alana erişildiğinde gerçekleşmesini önerir. Bunlardan hiçbiri yoksa hiç çalıştırılmayabilir mi?

[2018-10-09 CLR ekibi"Değer türleri için yaptıklarımızı yansıtacak (her örnek yöntemine erişimi denetleyen cctor"]

Karar: Statik oluşturucu beforefieldinitdeğilse, statik oluşturucular örnek yöntemlerine girişte de çalıştırılır. Bu durumda, statik oluşturucular ilk statik alana erişmeden önce çalıştırılır. https://github.com/dotnet/csharplang/blob/master/meetings/2018/LDM-2018-10-17.md#when-are-interface-static-constructors-run

Tasarım toplantıları

2017-03-08 LDM Toplantı Notları2017-03-21 LDM Toplantı Notları2017-03-23 toplantısı "CLR Davranışı için Varsayılan Arabirim Yöntemleri"2017-04-05 LDM Toplantı Notları2017-04-11 LDM Toplantı Notları2017-04-18 LDM Toplantı Notları2017-04-19 LDM Toplantı Notları2017-05-17 LDM Toplantı Notları2017-05-31 LDM Toplantı Notları2017-06-14 LDM Toplantı Notları2018-10-17 LDM Toplantı Notları2018-11-14 LDM Toplantı Notları