2008-10-31 16 views
16

Bugün bir C# sınıfının bir arabirimi hem örtülü hem de açık bir şekilde devralabileceğini görüyorum. Bu beni şaşırtıyor. C# bu şekilde çalışırsa, bir örnek farklı şekilde başvuruda bulunduğunda farklı davranabilir. kod çalışır ve çıkışNeden Bir C# Sınıfı Bir Arabirimden Hem İçten Hem de Açık Olarak Miras Olabilir mi?

do something implicitly 
do something explicitly 

Üstü

interface IFoo 
{ 
    void DoSomething(); 
} 

class Foo : IFoo 
{ 
    #region IFoo Members 
    public void DoSomething() 
    { 
     Console.WriteLine("do something implicitly"); 
    } 
    #endregion 

    #region IFoo Members 
    void IFoo.DoSomething() 
    { 
     Console.WriteLine("do something explicitly"); 
    } 
    #endregion 
} 


     Foo f = new Foo(); 
     f.DoSomething(); 

     ((IFoo)f).DoSomething(); 

C# bu tasarım davranışının tutarsızlık yapmak inanıyoruz. Belki bir C# sınıfının bir arabirimden örtük veya açık bir şekilde miras alması zorunludur, ancak her ikisi de değil.

neden C# şekilde tasarlandığını bir nedeni var mı?

+0

İkisini de yapabileceğinizi fark etmemiştim. Bu biraz aptalca görünüyor ... –

+0

Bu aptalca değil. Cevapları oku. –

+0

Çift-yeniden etiketleme konusunda üzgünüm, "açık arabirim-üyesi-uygulama" etiketini bir etiket olarak eklemeye çalışıyordum (bu, kullandığınız özelliğin adıdır), ancak görünüşe göre bu etiket çok uzun olacaktır. :) – Rytmis

cevap

11

Sizin örnek değil hem de örtük IFoo uygulamak yapar. Sadece IFoo.DoSometing() yöntemini açıkça uygularsınız. Sınıfında DoSomething() adında yeni bir yöntem var. IFoo.DoSomething ile hiçbir ilgisi yoktur, ancak aynı adı ve parametreleri vardır.

+0

Ve nasıl örtülü olarak uygulanıyordu? –

+0

yalnızca açık bir uygulama olmadığında –

+0

Yani, "C# sınıfı bir arabirimi aynı anda hem örtük hem de açık bir şekilde miras alabilir" aslında bir yanılsamadır. Bir sınıf aslında bir arayüzü bir kez miras alabilir. –

13

Bir arabirimi uygulayan her sınıf, o sınıfın üyeleri ve arabirimin üyeleri arasında eşleme eşlemesine sahiptir. sınıf açıkça bir arayüz elemanını uygulayan, o zaman açık uygulama hep arayüzüne eşleştirilir. Açık bir uygulama yoksa, örtülü bir uygulama beklenir ve bu arayüze eşlenecektir.

Bir sınıf da açıkça arabirimi için gelen elemanını uygulayan bir arayüz ama aynı üye adı ve ilişkili tipleri vardır

ardından sınıfının "örtük" uygulaması değil kabul arabiriminin bir uygulamasıdır (açık uygulama çağırılmadıkça). sınıf, hatta sadece bir ara yüz ile, aynı üye adı/türleriyle çok arabirimleri uygulayan her durumda farklı anlamları yanı sıra

, sınıfı kendisi aynı elemanının sahip olabilir örtülü bir arayüz sahip olduğu kabul edilir/tek arayüz olarak türleri ama yine de farklı bir şey demek.

+0

Bu örtülü arabirim gerçek bir arabirim mi, yoksa sadece bir arabirimi açığa çıkaran bir sınıf mıdır, yani bir tür de olsa, gizlenmiş olanı mı? – ProfK

+0

Sadece sınıfın ortaya çıkardığı şeylere başvuruyorum. CLR, bir sınıfın uygulaması ve kendi içsel arayüzü arasında fark yaratmaz (yani, başka bir sınıfın arayüzünü uygulayamazsınız ve arayüz ayrı olarak tanımlanmış bir Arabirim olmadığı sürece bunun yerini tutamazsınız). –

2

Çoklu kalıtım: Ne farklı amaçlar için aynı yöntemi tanımlayan iki arayüz kaynaklanıyor olur?

interface IMoveable 
    { 
    public void Act(); 
    } 

    interface IRollable 
    { 
    public void Act(); 
    } 

    class Thing : IMoveable, IRollable 
    { 
    //TODO Roll/Move code here 

    void IRollable.Act() 
    { 
     Roll(); 
    } 

    void IMoveable.Act() 
    { 
     Move(); 
    } 
    } 
7

Bu, çarpışma olduğunda daha esnek hale getirir. Özellikle, IEnumerator ve IEnumerator<T> bakmak - ikisi de ancak farklı türde bir Current özelliği vardır. Her iki uygulamak için açık arabirim uygulaması kullanmak sahip (ve jenerik formu olmayan jenerik formu uzanır).

+0

IIRC Bu, Jeff Richter'in C# üzerinden harika CLR'de EIMI'ler için kullandığı kesin örnektir. – Quibblesome

+0

Muhtemelen büyük bir faktör tarafından en sık ortaya çıkan budur :) –

+0

Ayrıca bu senaryoda "bu [dize]" özelliğini buldum. Dize dizinleyici ile bir sınıf vardı ve sonra IDataErrorInfo uygulamak istedim. Aynı problem - dize dizinleyicisini açıkça hata için uygulamak zorunda kaldım. –

0

Çocuklar, Cevaplarınız için teşekkürler.

"C# sınıfının aynı anda hem örtük hem de açık bir şekilde bir arabirimi miras alabildiği" ortaya çıkıyor, aslında bir yanılsama. Aslında, bir sınıf bir zaman için bir arabirimi miras alabilir.Özgün soruda, "DoSomething" yöntemi, IFoo (aslında VS2008 tarafından üretilen yöntem) arabiriminin "dolaylı olarak uygulanması" yöntemi gibi görünmektedir, ancak aslında OLDUĞU GİBİ DEĞİLDİR. IFoo arabiriminin açık bir şekilde uygulanmasıyla, "DoSomething" yöntemi, aynı imza dışında IFoo ile hiçbir ilgisi olmayan normal bir yöntem haline gelir.

Hala C# 'in zor bir tasarımı olduğuna inanıyorum ve yanlışlıkla kullanmak kolaydır. Diyelim ki, şu kodun bazı kodlarım var. Tamamen iyi görünüyor, ancak yürütme sonucu farklı.

 Action<IFoo> func = foo => foo.DoSomething(); 
     func(f); 
+1

Bu zor çünkü biri Foo'nun bir IFoo olduğunu tıpkı bir BaseFoo olduğu gibi düşünür ama değil! Bir Foo, bir IFoo'nun * rolünün * kaldırılması olarak daha iyi düşünülür ve bir IFoo'ya bir IFoo'ya eriştiğinizde, * rolünü ve * muhtemelen * davranışını da değiştirirsiniz. –

+0

Aslında, Foo sınıfının aynı isim ve parametrelerle iki farklı yönteme sahip olması zor bir tasarım olduğunu iddia edeceğim. İnsanları karıştırmak için kullanabileceğiniz başka bir örnek de, yeni anahtar kelimeyi bir yöntem değiştirici olarak kullanmaktır. Bunu asla kullanmam çünkü kafa karıştırıcı, ama bir güne ihtiyacım olabilir. – Hallgrim

İlgili konular