Arabirimde tanımlanan C # 4 isteğe bağlı parametreler neden sınıf uygulamada uygulanmıyor?


361

C # 4'teki isteğe bağlı parametrelerle, bir arabirimde isteğe bağlı bir parametre belirtirseniz , bu parametreyi herhangi bir uygulama sınıfında isteğe bağlı yapmak zorunda olduğunuzu fark ettim :

public interface MyInterface
{
    void TestMethod(bool flag = false);
}

public class MyClass : MyInterface
{
    public void TestMethod(bool flag)
    {
        Console.WriteLine(flag);
    }
}

ve bu nedenle:

var obj = new MyClass();        
obj.TestMethod(); // compiler error

var obj2 = new MyClass() as MyInterface;
obj2.TestMethod(); // prints false

İsteğe bağlı parametrelerin neden bu şekilde çalışmak üzere tasarlandığını bilen var mı?

Bir yandan, arayüzlerde belirtilen herhangi bir varsayılan değeri geçersiz kılma yeteneğinin, dürüst olmak gerekirse yararlı olduğunu varsayalım.

Öte yandan, bu bağlantı kesme beton sınıfını ve arayüzü her zaman birbirinin yerine kullanamayacağınız anlamına gelir. Bu, elbette, uygulamada varsayılan değer belirtilirse sorun olmaz, ancak daha sonra somut sınıfınızı arayüz olarak ortaya koyarsanız (örneğin somut sınıfı enjekte etmek için bazı IOC çerçevelerini kullanarak), o zaman gerçekten çağıran varsayılan değere sahip olan nokta, her zaman yine de onu belirtmek zorunda kalacaktır.


22
İsteğe bağlı oldukları için?
Oded

1
Ancak nesne örneğini atayabilir MyInterfaceve isteğe bağlı parametre ile çağırabilirsiniz ((MyInterface)obj).TestMethod();.
Jim Mischel

7
@oded - ancak bu parametrenin sözleşmede isteğe bağlı olduğunu söylüyorsanız, uygulayıcının neden isteğe bağlı yapmamasına izin veriyorsunuz? Bu sadece sözleşmeyi kullanmak isteyen herkes için karışıklığa neden olmaz mı?
theburningmonk

1
Bu durumda parametre uygulama yöntemlerini çağırmak değil, uygulama isteğe bağlı olduğunu söyleyebiliriz.Sınıftaki yöntemi çağırdığınızda sınıf kurallarını (parametre sınıfta isteğe bağlı değildir) '' yöntemi onsuz çağırmayın) ve ikinci elinde arabirimi uyguladığınızda arabirim kurallarına uymanız gerekir, böylece isteğe bağlı parametrelerle / parametrelere sahip olmayan yöntemleri geçersiz kılabilirsiniz. Sadece bir fikir.
Mohamad Alhamoud

2
Burada daha ayrıntılı sorun açıklaması -> geekswithblogs.net/BlackRabbitCoder/archive/2010/06/17/…
Andrew Orsich

Yanıtlar:


236

GÜNCELLEME: Bu soru 12 Mayıs 2011'deki blogumun konusuydu. Harika soru için teşekkürler!

Açıkladığınız gibi bir arayüzünüz ve onu uygulayan yüz sınıfınız olduğunu varsayalım. Ardından, arabirimin yöntemlerinden birinin parametrelerinden birini isteğe bağlı yapmaya karar verirsiniz. Yapılacak doğru şeyin, derleyicinin geliştiriciyi bu arabirim yönteminin her uygulamasını bulmaya zorlaması ve parametreyi isteğe bağlı hale getirmesi olduğunu mu düşünüyorsunuz?

Diyelim ki bunu yaptık. Şimdi geliştiricinin uygulama için kaynak koduna sahip olmadığını varsayalım:


// in metadata:
public class B 
{ 
    public void TestMethod(bool b) {}
}

// in source code
interface MyInterface 
{ 
    void TestMethod(bool b = false); 
}
class D : B, MyInterface {}
// Legal because D's base class has a public method 
// that implements the interface method

D'nin yazarı bu işi nasıl yapacak? Dünyanızda telefonun B yazarını çağırmaları ve onlara yöntemin isteğe bağlı bir parametresi olmasını sağlayan B'nin yeni bir sürümünü göndermelerini istemeleri gerekiyor mu?

Bu uçmayacak. Ya iki kişi B'nin yazarını çağırırsa ve bunlardan biri varsayılanın doğru olmasını ister ve biri yanlış olmasını isterse? Ya B'nin yazarı oynamayı reddederse?

Belki de bu durumda şunları söylemeleri gerekir:

class D : B, MyInterface 
{
    public new void TestMethod(bool b = false)
    {
        base.TestMethod(b);
    }
}

Önerilen özellik, temsilci gücünde karşılık gelen bir artış olmadan programcı için çok fazla rahatsızlık katıyor gibi görünüyor. Bu özelliğin kullanıcıya artan maliyeti haklı çıkartan faydası nedir?


GÜNCELLEME: Aşağıdaki yorumlarda supercat, dile gerçekten güç katacak ve bu soruda anlatılanlara benzer bazı senaryoları etkinleştirecek bir dil özelliği önerir. Bu özellik - arayüzlerdeki yöntemlerin varsayılan uygulamaları - C # 8'e eklenecektir.


9
@supercat: Bunu yapmak için bir planımız yok, ancak bunun gibi bir özellik mümkün. Daha önce önerilmişti. C # 4 için tasarım sürecinde "her şeyi genişlet" özellikleri dediğimiz şeylerin çoğunu başlattık - genişletme yöntemlerine sahibiz, bu yüzden genişletme olayları, genişletme özellikleri, genişletme kurucuları, genişletme arabirimleri vb. . Arabirimlere "ekleyebileceğiniz" ve "bu yöntemler bu arabirimin varsayılan uygulamalarıdır" diyebileceğiniz sınıflar, "uzantı arabirimlerini" karakterize etmenin olası yollarından biridir. İlginç bir fikir.
Eric Lippert

16
neden sezgisel olmadığını düşünüyorum benim neden açıklığa kavuşturmak için: bana isteğe bağlı bir parametre "yöntemin arayan için isteğe bağlı" DEĞİL "arabirimin uygulayıcı için isteğe bağlı".
Stefan de Kok

8
"Dünyanızda telefonun B yazarını çağırmaları ve onlara yeni bir sürüm göndermelerini rica etmeleri gerekiyor mu [...]?" Hayır, telefon görüşmesi gerekmez. B artık MyInterface uygulamasının bir implentasyonu olarak kabul edilemez ve D'nin yazarı derleyici tarafından bundan haberdar edilebilir. D yazarının D'yi, Arabirim yazarının gerektirdiği gibi varsayılan bir parametreyi kabul eden bir TestMethod ile uygulaması gerekecektir - birisinin onu kırmak isteyebileceği için arayüz yazarının bir kısıtlama uygulamasına izin vermeyi tartışıyorsunuz. Bu iyi bir argüman değil.
philofinfinitejest

7
@EricLippert Kodlama kolaylığı için isteğe bağlı parametrenin belirtildiği durumda, evet, uygulamadaki zorluğun zorlanması karşı sezgiseldir. Ancak yöntem aşırı yüklemesini en aza indirmek için isteğe bağlı parametrenin kullanıldığı durumda, güçlü bir özellik, bu isteğe bağlı değerler büyük önem kazanabilir ve bunları görmezden gelmek kesinlikle bu gücü seyreltir. Somut uygulamanın arayüzden farklı bir varsayılan değer belirttiği durumdan bahsetmiyoruz bile. İzin vermek için çok garip bir bağlantı gibi görünüyor.
philofinfinitejest

8
Burada @philofinfinitejest ile hemfikirim. Bir arayüz bir şeyin ne yapabileceğini söyler. Arabirimin belirttiğinden farklı bir varsayılan değere sahip bir arabirimin uygulanmasından geçtiysem bunu nasıl bilebilirim? Hey, varsayılan olarak doğru geçen bir arayüzüm var, neden bu şey yanlış oluyor? Bu, beklediğim arayüzü alamadım gibi görünüyor. Daha da kötüsü, artık bir arayüze değil, bir uygulamaya programlamak zorundayım.
aaronburro

47

İsteğe bağlı bir parametre yeni bir özellikle etiketlenir. Bu öznitelik derleyiciye çağrı sitesinde o parametre için varsayılan değeri eklemesini söyler.

CIT kodu JIT zamanında değil, IL'ye derlendiğinde çağrı obj2.TestMethod();ile değiştirilir obj2.TestMethod(false);.

Yani bir şekilde her zaman arayan isteğe bağlı parametrelerle varsayılan değeri sağlar. Bunun ikili sürüm oluşturmada da sonuçları vardır: Varsayılan değeri değiştirir ancak arama kodunu yeniden derlemezseniz, eski varsayılan değeri kullanmaya devam eder.

Öte yandan, bu bağlantı kesme beton sınıfını ve arayüzü her zaman birbirinin yerine kullanamayacağınız anlamına gelir.

Arayüz yöntemi açıkça uygulanmışsa bunu zaten yapamazsınız .


1
Yine de uygulayıcıları açıkça uygulamaya zorlayabilir misiniz?
ezmek

30

Varsayılan parametreler çalışma zamanında değil, derleme zamanında çözümlendiğinden. Dolayısıyla, varsayılan değerler çağrılan nesneye değil, çağrıldığı referans türüne aittir.


7

İsteğe bağlı parametreler, anladığımdan bir makro ikamesi gibidir. Yöntemin bakış açısından gerçekten isteğe bağlı değildirler. Bunun bir artefaktı, bir arayüze yayın yaparsanız farklı sonuçlar elde ettiğiniz yerde gördüğünüz davranıştı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.