C # 'daki üyeleri gizlemek için açık arabirim uygulaması kullanma izni var mı?


14

C # arayüzleri ve açık arabirim uygulaması ile nasıl çalışacağını anlıyorum, ancak sık kullanılmayacak belirli üyeleri gizlemek için kötü bir form olarak kabul edilip edilmediğini merak ediyordum. Örneğin:

public interface IMyInterface
{
    int SomeValue { get; set; }
    int AnotherValue { get; set; }
    bool SomeFlag { get; set; }

    event EventHandler SomeValueChanged;
    event EventHandler AnotherValueChanged;
    event EventHandler SomeFlagChanged;
}

Olayların yararlı olsa da çok nadiren kullanılacağını önceden biliyorum. Bu nedenle, IntelliSense karmaşasından kaçınmak için onları açık bir uygulama yoluyla bir uygulayıcı sınıftan gizlemenin mantıklı olacağını düşündüm.


3
Örneğinize arabirim aracılığıyla atıfta bulunursanız, onları yine de gizlemezdi, yalnızca referansınız somut bir türdeyse gizlenir.
Andy

1
Bunu düzenli olarak yapan bir adamla çalıştım. Beni kesinlikle deli ediyordu.
Joel Etherton

... ve toplama kullanmaya başlayın.
mikalai

Yanıtlar:


39

Evet, genellikle kötü bir formdur.

Bu nedenle, IntelliSense karmaşasından kaçınmak için onları açık bir uygulama yoluyla bir uygulayıcı sınıftan gizlemenin mantıklı olacağını düşündüm.

IntelliSense'iniz çok dağınıksa, sınıfınız çok büyük. Sınıfınız çok büyükse, çok fazla şey yapıyor ve / veya kötü tasarlanmış.

Sorununuzu düzeltin, belirtinizi değil.


Kullanılmayan üyeler hakkındaki derleyici uyarılarını kaldırmak için kullanmak uygun mudur?
Gusdor

11
"Sorununuzu değil, belirtinizi düzeltin." +1
FreeAsInBeer

11

Özelliği, amaçlandığı gibi kullanın. Ad alanı karmaşasını azaltmak bunlardan biri değil.

Meşru nedenler "gizlemek" veya organizasyonla ilgili değildir, belirsizliği çözmek ve uzmanlaşmak içindir. "Foo" tanımlayan iki arabirim uygularsanız, Foo'nun semantiği farklı olabilir. Açık arabirimler dışında bunu çözmek için gerçekten daha iyi bir yol değil. Alternatif, çakışan arayüzlerin uygulanmasına izin vermemek veya arayüzlerin anlambilimi ilişkilendiremeyeceğini bildirmektir (bu zaten kavramsal bir şeydir). Her ikisi de zayıf alternatiflerdir. Bazen pratiklik zarafeti yitirir.

Bazı yazarlar / uzmanlar bunun bir özellik küfürü olduğunu düşünmektedir (yöntemler türün nesne modelinin bir parçası değildir). Ancak tüm özellikler gibi, bir yerlerde de birinin buna ihtiyacı vardır.

Yine, olur değil gizleme veya kuruluş için kullanabilirsiniz. Üyeleri zekâdan gizlemenin yolları vardır.

[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]

Diyerek şöyle devam etti: "Bunu bir özelliğin küfürü olarak kabul eden önde gelen yazarlar / uzmanlar var." Kim? Önerilen alternatif nedir? Açık uygulama yokluğunda çözmek için C # 'a eklenecek en az bir sorun (yani bir alt arayüz / uygulama sınıfında arayüz yöntemlerinin uzmanlaşması) vardır (bkz. ADO.NET ve genel koleksiyonlar) .
jhominal

@jhominal - Jeffrey Richter tarafından C # üzerinden CLR özellikle kludge kelimesini kullanır. C ++ onsuz anlaşır, programcı açıkça tanımlamak veya bir döküm kullanmak için temel yöntem uygulamasına başvurmalıdır. Alternatiflerin çok cazip olmadığını söylemiştim. Ama bu genel olarak OOP değil, tek miras ve arayüzlerin bir yönü.
codenheim

Aynı "uygulama + arayüzlerin tek mirası" tasarımına sahip olmasına rağmen, Java'nın açık bir uygulamaya sahip olmadığını da söyleyebilirsiniz. Bununla birlikte, Java'da, geçersiz kılma yönteminin döndürme türü özelleştirilebilir ve bu da açık uygulama ihtiyacının bir kısmını ortadan kaldırır. (C # 'da, muhtemelen kısmen mülklerin dahil edilmesi nedeniyle farklı bir tasarım kararı alınmıştır).
jhominal

@jhominal - Elbette, birkaç dakika sonra güncelleyeceğim. Teşekkürler.
codenheim

Gizleme, bir sınıfın arayüz sözleşmesine uyan ancak kullanışlı olmayan bir şekilde bir arayüz yöntemi uygulayabileceği durumlarda tamamen uygun olabilir . Örneğin, bir IDisposable.Disposeşey yapan ancak farklı bir ad verilen sınıflar fikrinden hoşlanmama rağmen Close, sözleşmesi açıkça kodun Disposeaçık arabirim uygulamasını kullanmaya çağırmadan örnekler oluşturabileceğini ve terk edebileceğini belirttiği bir sınıf için mükemmel makul olduğunu düşünürdüm . IDisposable.Disposehiçbir şey yapmayan bir yöntem tanımlar .
supercat

5

Dağınık kodun bir işareti olabilirim, ama bazen gerçek dünya dağınık. .NET çerçevesinden bir örnek, değiştirici ayarlayıcı [], Ekle ve Ayarla'yı gizleyen ReadOnlyColection'dur .

IE ReadOnlyCollection IList <T> uygular. Birkaç yıl önce bunu düşündüğümde SO'ya olan sorumu da görün .


Ben de kullanacağım kendi arayüzüm, bu yüzden baştan itibaren yanlış yapmanın bir anlamı yok.
Kyle Baran

2
Mutasyona uğrayan ayarlayıcıyı gizlediğini söylemezdim, aksine bunu hiç sağlamaz. A ) tüketicileri doğrudan çağırmayacak ve B) kesinlikle gerekliyse uygulanmasını gerektiren yöntemleri kullanabilmeleri için ConcurrentDictionaryçeşitli üyeleri IDictionary<T>açıkça uygulayan daha iyi bir örnek olacaktır . Örneğin, kullanıcıları gerektiğini çağırmak yerine gereksiz istisnalar gerek önlemek için. ConcurrentDictionaryIDictionary<T>ConcurrentDictionary<T> TryAddAdd
Brian

Tabii ki, Addaçıkça uygulanması da dağınıklığı azaltır. TryAddyapabileceği her şeyi Addyapabilir ( Addçağrı olarak uygulanır TryAdd, böylece her ikisinin de sağlanması gereksizdir). Bununla birlikte, TryAddmutlaka farklı bir ad / imzası vardır, bu nedenle IDictionarybu fazlalık olmadan uygulamak mümkün değildir . Açık uygulama bu sorunu temiz bir şekilde çözer.
Brian

Tüketici açısından yöntemler gizlidir.
Esben Skov Pedersen

1
IReadonlyCollection <T> hakkında yazıyorsunuz ancak ReadOnlyCollection <T> 'a bağlantı veriyorsunuz. Bir arayüzde birincisi, ikincisi bir sınıftır. IReadonlyCollection <T>, ReadonlyCollection <T> uygulamasına rağmen IList <T> uygulamıyor.
Jørgen Fogh

2

Üye bağlamda anlamsız olduğunda bunu yapmak iyi bir formdur. Örneğin, IList<T>dahili bir nesneye yetki vererek uyguladığınız salt okunur bir koleksiyon oluşturursanız, şöyle bir _wrappedşeye sahip olabilirsiniz:

public T this[int index]
{
  get
  {
     return _wrapped[index];
  }
}
T IList<T>.this[int index]
{
  get
  {
    return this[index];
  }
  set
  {
    throw new NotSupportedException("Collection is read-only.");
  }
}
public int Count
{
  get { return _wrapped.Count; }
}
bool ICollection<T>.IsReadOnly
{
  get
  {
    return true;
  }
}

Burada dört farklı vakamız var.

public T this[int index]arayüzden ziyade sınıfımız tarafından tanımlanır ve bu nedenle elbette açık bir uygulama değildir, ancak T this[int index]arayüzde tanımlanan okuma-yazma işlemine benzediğini, ancak salt okunur olduğunu unutmayın .

T IList<T>.this[int index]açıktır, çünkü bir kısmı (alıcı) yukarıdaki mülkle mükemmel bir şekilde eşleşir ve diğer kısmı her zaman bir istisna atar. Arayüz yoluyla bu sınıfın bir örneğine erişen biri için hayati olmakla birlikte, sınıf türünün bir değişkeni aracılığıyla kullanan birisinin anlamı yoktur.

Benzer şekilde bool ICollection<T>.IsReadOnly, her zaman doğru döneceğinden, sınıfın türüne karşı yazılan kodu tamamen anlamsızdır, ancak arayüzün türü aracılığıyla bunu kullanması için hayati önem taşıyabilir ve bu nedenle açıkça uygularız.

Buna karşılık, public int Countkendi türüyle bir örneği kullanan biri için potansiyel olarak yararlı olabileceğinden açıkça uygulanmaz.

Ancak "çok nadiren kullanılan" durumunuzla, açık bir uygulama kullanmamaya çok güçlü bir şekilde eğilirim.

Sınıf türünün bir değişkeni yoluyla yöntemi çağıran açık bir uygulama kullanmanızı öneririm durumlarda ya bir hata (dizinlenmiş ayarlayıcıyı kullanmaya çalışırken) ya da anlamsız (her zaman aynı olacak bir değeri denetleme) kullanıcıyı buggy veya en uygun olmayan koddan koruyorsunuz. Bu, nadiren kullanıldığını düşündüğünüz koddan önemli ölçüde farklıdır . Bunun için EditorBrowsableüyeyi zekâdan gizlemek için bu özelliği kullanmayı düşünebilirim ; insanların beyninin zaten ilgilerini çekmeyen şeyleri filtrelemek için kendi yazılımları var.


Bir arabirim uyguluyorsanız , arabirimi uygulayın. Aksi takdirde, bu Liskov İkame İlkesinin açık bir ihlalidir.
Telastyn

@Telastyn arayüzü gerçekten uygulandı.
Jon Hanna

Ancak sözleşmesi tatmin olmuyor - özellikle "Bu değişebilir, rastgele erişim koleksiyonunu temsil eden bir şey".
Telastyn

1
@Telastyn, özellikle "Salt okunur bir koleksiyon, koleksiyon oluşturulduktan sonra öğelerin eklenmesine, kaldırılmasına veya değiştirilmesine izin vermez" ışığında dokümante edilmiş sözleşmeyi yerine getirir. Bkz. Msdn.microsoft.com/en-us/library/0cfatk9t%28v=vs.110%29.aspx
Jon Hanna

@Telastyn: Sözleşme değişebilirlik içeriyorsa, arayüz neden bir IsReadOnlyözellik içeriyor ?
nikie
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.