Neden C # arabirimleri alan içeremez?


223

Örneğin, bir ICararayüz istediğimi ve tüm uygulamaların alanı içerdiğini varsayalım Year. Bu, her uygulamanın ayrı ayrı beyan etmesi gerektiği anlamına mı geliyor Year? Bunu arayüzde tanımlamak daha hoş olmaz mıydı?


21
Arabirimler uygulama yok, bu kullanım için soyut bir sınıf, yıl özelliği ile
PostMan

6
Burada söylenenlere eklemek için, arabirimler sözleşmelerdir ve bir alan, bir değer (skaler veya adres işaretçisi) koymak için makinenin belleğindeki bir yuvayı tanımladığı bir uygulama detayıdır.
herzmeister

5
Ama eğer alan halka açıksa, sadece bir uygulama detayı değil, sözleşmenin bir parçası değil mi?
Alex

Yanıtlar:


238

Diğer cevapların çoğu semantik düzeyde doğru olsa da, bu tür sorulara uygulama ayrıntıları seviyesinden de yaklaşmayı ilginç buluyorum.

Bir arayüz, yöntemler içeren bir yuva koleksiyonu olarak düşünülebilir . Bir sınıf bir arabirim uyguladığında, sınıfın çalışma zamanına gerekli tüm yuvaları nasıl dolduracağını bildirmesi gerekir. Dediğinde

interface IFoo { void M(); } 
class Foo : IFoo { public void M() { ... } }

"Benim örneğimi oluşturduğunuzda, IFoo.M için yuvadaki Foo.M'ye bir referans girin.

Sonra bir çağrı yaptığınızda:

IFoo ifoo = new Foo();
ifoo.M();

derleyici "nesneye IFoo.M için yuvada hangi yöntemin sormak ve bu yöntemi çağırmak" yazan kod üretir.

Arabirim, yöntemleri içeren bir yuva koleksiyonuysa, bu yuvalardan bazıları bir özelliğin get ve set yöntemlerini, bir dizinleyicinin get ve set yöntemlerini ve bir olayın ekleme ve kaldırma yöntemlerini de içerebilir. Ancak bir alan bir yöntem değildir . Alanla ilişkilendirilmiş bir "yuva" yoktur ve bu alan alanına referansla "doldurabilirsiniz". Bu nedenle arabirimler yöntemleri, özellikleri, dizinleyicileri ve olayları tanımlayabilir, ancak alanları tanımlayamaz.


26
Bazen özlediğim tek şey, muhtemelen dilde desteklenmesi için bir "yuva" gerektirmeyecek arayüz düzeyinde sabitleri tanımlamak için java benzeri bir yetenek.
LBushkin

2
Açıklamayı basit sözlerle seviyorum. Teşekkürler. "C # üzerinden CLR" ve "Temel .net hacmi 1" daha fazla ayrıntı sağlar.
Sandeep GB

6
Neden bir alanın yuvası yok? ve operatörlerle aynı soru? Sınıf arabirimi devralmamış olsa bile bir arabirimin uygulanıp uygulanmadığını görmek için yansıma kullanarak ördek yazmayı duyduğumu hatırlıyorum. Bir alanı çekmek için neden yansıma (veya bir yuva) kullanılamıyor? ben hala benim kod yazıyorum bu yüzden / alanlar gerek olmayabilir ama ben operatörleri kullanamazsınız bulmak için sürpriz oldu. Operatörler tam tüm aşırı yüklenebilir değil haricinde benim anlayış yöntemlerle gibidirler ( An interface cannot contain constants, fields, operatorsDan. msdn.microsoft.com/en-us/library/ms173156.aspx )

@acidzombie: Bir arabirimin neden işleçleri tanımlayamadığı sorusu, neden alanları içeremediğinden farklı olabilir (belki de ilişkili olabilir); Hala ilgileniyorsanız başka bir soru göndermenizi öneririm.
Adam Robinson

1
@ b1nary.atr0phy neden alanlar? Örneğin, bir yöntem beyan ettiysem int One(), uygulama public int One(){return 1;}bir alan değildir.
Hi-Angel

131

C # 'daki arabirimler, bir sınıfın yapışacağı sözleşmeyi tanımlamayı amaçlamaktadır - belirli bir uygulama değil.

Bu ruh haliyle, C # arabirimleri , çağıranın aşağıdakiler için bir uygulama sağlaması gereken özelliklerin tanımlanmasına izin verir :

interface ICar
{
    int Year { get; set; }
}

Özelliklerle ilişkilendirilmiş özel bir mantık yoksa, uygulama sınıfları, uygulamayı basitleştirmek için otomatik özellikleri kullanabilir:

class Automobile : ICar
{
    public int Year { get; set; } // automatically implemented
}

5
Kamuya açık olan her şey sözleşmenin bir parçası değil. Bir sınıfın kamu int Yılı varsa, sınıf sözleşmesinin üzerinde mevcut ve erişilebilir bir yıl alanı olduğu söylenemez mi?
Didier

1
Partiye geç, ama hayır, bu durumda sözleşmenin, herhangi bir uyan sınıfın uygulaması gereken bir MÜLK Yılı olduğu anlamına gelir. Özellikler aslında özel bir mantık gerekmiyorsa yedekleme alanı otomatik olarak oluşturulan get / set yöntemleridir. Özel sözdizimi sadece daha net bir gösterim içindir.
user3613916

Otomatik uygulaması için sabit bir varsayılan değeri (123 gibi) nasıl tanımlayabilirim Year?
lama12345

1
@ lama12345 Ayrıca partiye geç kaldım, ancak C # 6'dan (2015, .NET Framework 4.6 ve .NET Core) bu amaçla bir otomatik özellik kullanabilirsiniz. public int Year => 123;. Bununla birlikte, bu durumda bir ayarlayıcıya sahip olmanın bir anlamı yoktur, bu nedenle arayüzint Year { get; }
EriF89

56

Mülk olarak beyan edin:

interface ICar {
   int Year { get; set; }
}

47
Soru " C # arabirimleri neden alanlar içeremez?" Sorusudur. Bu bunu ele almıyor.
AakashM

14
Bu cevabın OP sorusuna cevap vermediğini kabul ediyorum, ama sorunumu çözdü.
Gorgen

36

Eric Lippert çivilenmiş, söylediklerini söylemek için farklı bir yol kullanacağım. Bir arabirimin tüm üyeleri sanaldır ve hepsinin arabirimi devralan bir sınıf tarafından geçersiz kılınması gerekir. Sanal anahtar sözcüğü arabirim bildirimine açıkça yazmaz veya sınıfta geçersiz kılma anahtar sözcüğünü kullanmazsınız.

Sanal anahtar kelime yöntemleri ve yöntem işaretçileri bir dizi v-table denilen .NET ile uygulanır. Override anahtar sözcüğü, v-table yuvasını, temel sınıf tarafından üretilenin üzerine yazarak farklı bir yöntem işaretçisiyle doldurur. Özellikler, olaylar ve dizinleyiciler başlık altında yöntem olarak uygulanır. Ancak alanlar değildir. Arayüzler bu nedenle alan içeremez.


Eric tarafından belirtilen yuva kavramına teknik / gerçek adı (v-tablosu) girdiniz. Detay için teşekkürler Hans.
RBT

Arabirimler varsayılan uygulamalara izin verilmezse v-tablonun anlamı ne olur? Bu C # 8.0 değişir, ama bu nokta yanında.
AnthonyMonterrosa

19

Neden sadece Yeargayet iyi bir mülke sahip değilsiniz ?

Alanlar, veri temsili için belirli bir uygulamayı temsil ettiğinden ve bunları ortaya çıkarmak kapsüllemeyi keseceğinden, alanlar içermez. Böylece, bir alanla bir arayüze sahip olmak, bir arayüze sahip olmak için bir uygulama yerine etkili bir şekilde kodlama yapar;

Örneğin, Yearbelirtiminizin bir kısmı, ICaruygulayıcıların Yeargeçerli yıl + 1'den veya 1900'den önceki bir süreye atamaya izin vermesinin geçersiz olmasını gerektirebilir . Açıkta kalan Yearalanlarınız varsa - kullanmak çok daha iyi burada iş yapmak yerine özellikleri.


18

Kısa cevap evet, her uygulama tipinin kendi destek değişkenini yaratması gerekecek. Bunun nedeni, bir arabirimin bir sözleşmeye benzer olmasıdır. Yapabileceği tek şey, bir uygulama türünün kullanıma sunması gereken genel olarak erişilebilir kod parçalarını belirtmektir; herhangi bir kod içeremez.

Önerilerinizi kullanarak bu senaryoyu düşünün:

public interface InterfaceOne
{
    int myBackingVariable;

    int MyProperty { get { return myBackingVariable; } }
}

public interface InterfaceTwo
{
    int myBackingVariable;

    int MyProperty { get { return myBackingVariable; } }
}

public class MyClass : InterfaceOne, InterfaceTwo { }

Burada birkaç sorunumuz var:

  • Bir arabirimin tüm üyeleri - tanım gereği - herkese açık olduğundan, destek değişkenimiz artık arabirimi kullanan herkese açıktır
  • Hangi myBackingVariableolacak MyClasskullanabilir?

En yaygın yaklaşım, arayüzü ve onu uygulayan bir barebone soyut sınıfını ilan etmektir. Bu, soyut sınıftan miras alma ve uygulamayı ücretsiz alma veya arabirimi açıkça uygulama ve başka bir sınıftan miras alma esnekliğine izin verir. Bunun gibi bir şey çalışır:

public interface IMyInterface
{
    int MyProperty { get; set; }
}

public abstract class MyInterfaceBase : IMyInterface
{
    int myProperty;

    public int MyProperty
    {
        get { return myProperty; }
        set { myProperty = value; }
    }
}

7

Diğerleri 'Neden' verdi, bu yüzden sadece arayüzünüzün bir Kontrol tanımlayabileceğini ekleyeceğim; bir mülke sararsanız:

public interface IView {
    Control Year { get; }
}


public Form : IView {
    public Control Year { get { return uxYear; } } //numeric text box or whatever
}

3

Arabirimler herhangi bir uygulama içermez.

  1. Özelliğe sahip bir arabirim tanımlayın.
  2. Ayrıca bu arabirimi herhangi bir sınıfta uygulayabilir ve bu sınıfı ileride kullanabilirsiniz.
  3. Gerekirse, davranışını değiştirebilmeniz için bu özelliğin sınıfta sanal olarak tanımlanmasını sağlayabilirsiniz.

3

Şimdiden çok şey söylendi, ancak basitleştirmek için benim almam. Arayüzler, tüketiciler veya sınıflar tarafından uygulanacak yöntem sözleşmelerine sahip olacak ve değerleri depolayacak alanlara sahip olmayacak şekilde tasarlanmıştır.

O zaman neden özelliklere izin verildiğini iddia edebilirsiniz? Yani basit cevap - özellikler dahili olarak sadece yöntem olarak tanımlanır.


1
Bir üyeye erişmeniz gerekiyorsa, onu bir mülk haline getirin ve iyi olacaksınız.
16'da Unome

0

Bunun için yıl alanını uygulayan bir Car temel sınıfına sahip olabilirsiniz ve diğer tüm uygulamalar bundan miras alabilir.


0

Bir arabirim, genel yönetim ortamı özelliklerini ve yöntemlerini tanımlar . Alanlar tipik olarak özeldir veya en fazla korunan, dahili veya korunan iç kısımdadır ("alan" terimi genellikle herkese açık hiçbir şey için kullanılmaz).

Diğer yanıtlarda belirtildiği gibi, bir temel sınıf tanımlayabilir ve tüm mirasçılar tarafından erişilebilecek korumalı bir özellik tanımlayabilirsiniz.

Bir gariplik, bir arayüzün aslında dahili olarak tanımlanabilmesidir, ancak arayüzün kullanışlılığını sınırlar ve tipik olarak diğer harici kodlar tarafından kullanılmayan dahili işlevselliği tanımlamak için kullanılır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.