Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
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çin
Şampiyon konusu: https://github.com/dotnet/csharplang/issues/52
Özet
Somut uygulamalara sahip arabirimlerdeki yöntemler
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
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, M
iç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
, extern
ve 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 virtual
olacak 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 sealed
değ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
veinternal
gibi 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?
: Dönüştürme, eşitlik ve eşitsizlik işleçleri için dışında işleçlere Karar 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 sealed
bildirilmeyebilir.
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.M
bildiriminde 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 M1
T1
türünde bildirilmişse, M2
T2
türünde bildirilmişse ve/veya.
-
T1
, doğrudan veya dolaylı arabirimleri arasındaT2
içerir veya -
T2
bir arabirim türüdür ancakT1
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 olarakvirtual
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).M
ifadesini 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).M
kullanı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
Bir arabirimin doğrudan veya dolaylı olarak kendisinden devralması derleme zamanı hatasıdır.
Bir arabirimin
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
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:
- Bu özelliğin bazı kullanıcılarının birlikte çalışabilmeyi umduğu Java API'leri bu tesise bağlıdır.
- ö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ı
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
virtual
olmalıdır? [EVET]
Kararları: LDM 2017-04-05'te Alındı.
- sanal olmayanlar açıkça
sealed
veyaprivate
aracılığıyla ifade edilmelidir. -
sealed
, gövdeleri sanal olmayan arabirim örneği nesne üyeleri yapmak için kullanılan anahtar sözcüktür. - Arabirimlerdeki tüm değiştiricilere izin vermek istiyoruz
- İç içe türler de dahil olmak üzere arabirim üyeleri için varsayılan erişilebilirlik geneldir
- arabirimlerdeki özel fonksiyon üyeleri kendiliğinden mühürlenmiştir ve
sealed
üzerlerinde kullanılamaz. - 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.
- 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.M
olduğ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
-
I1.M
çalıştırır -
I2.M
çalıştırır - 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
,M2
türünde bildirilirse,M1
T1
türünde bildirilirse, başka bir geçersiz kılmaM2
T2
kabul edilir.
T1
, doğrudan veya dolaylı arabirimleri arasındaT2
içerir veyaT2
bir arabirim türüdür ancakT1
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:
- Bir
struct
'nin varsayılan bir uygulamayı devralmasını yasakla. Tüm arabirim yöntemleri birstruct
içinde soyut olarak ele alınmalıdır. Daha sonra nasıl daha iyi çalışabileceğine karar vermek için zaman ayırabiliriz.- Kutulamadan kaçınacak bir kod oluşturma stratejisi geliştirin.
IB.Increment
gibi bir yöntemin içindethis
türü,IB
kı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.- O konuda endişelenmeyin ve onu siğil olarak bırakın.
- 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ı yoksavoid 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.M
olduğ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
-
I1.M
çalıştırır -
I2.M
çalıştırır -
I3.M
çalıştırır - 2 veya 3, belirleyici
- 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ı partial
bildirmek yararlı olabilir. Bu özellikle jeneratörler karşısında yararlı olacaktır.
Teklifi: Arabirimlerin ve arabirim üyelerinin
partial
bildirilmeyebileceğ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.
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 beforefieldinit
değ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ı
C# feature specifications