Mengapa parameter opsional C # 4 didefinisikan pada antarmuka tidak diberlakukan pada kelas implementasi?

361

Saya perhatikan bahwa dengan parameter opsional di C # 4 jika Anda menentukan parameter opsional pada antarmuka yang Anda tidak perlu t membuat parameter itu opsional pada setiap kelas pelaksana:

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

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

dan oleh karena itu:

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

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

Adakah yang tahu mengapa parameter opsional dirancang untuk bekerja seperti ini?

Di satu sisi saya kira kemampuan untuk menimpa nilai default apa pun yang ditentukan pada antarmuka berguna meskipun jujur ​​saya tidak yakin apakah Anda bahkan dapat menentukan nilai default pada antarmuka karena itu harus menjadi keputusan implementasi.

Di sisi lain, pemutusan ini berarti Anda tidak bisa selalu menggunakan kelas konkret dan antarmuka secara bergantian. Ini tentu saja, tidak akan menjadi masalah jika nilai default ditentukan pada implementasi, tetapi kemudian jika Anda mengekspos kelas beton Anda sebagai antarmuka (menggunakan beberapa kerangka kerja IOC untuk menyuntikkan kelas beton misalnya) maka benar-benar tidak ada titik memiliki nilai default sebagai penelepon harus selalu memberikannya.

theburningmonk
sumber
22
Karena mereka opsional?
Oded
1
Tapi Anda bisa melemparkan contoh objek untuk MyInterfacedan menyebutnya dengan parameter opsional: ((MyInterface)obj).TestMethod();.
Jim Mischel
7
@oded - tetapi jika Anda mengatakan parameter ini opsional pada kontrak, mengapa Anda mengizinkan implementer untuk tidak menjadikannya opsional? bukankah itu hanya menimbulkan kebingungan bagi siapa pun yang ingin menggunakan kontrak?
theburningmonk
1
Saya pikir dalam hal ini Anda dapat mengatakan bahwa parameter adalah opsional dalam mengimplementasikan, bukan dalam memanggil metode pelaksanaan. Ketika Anda memanggil metode di kelas Anda harus mengikuti aturan kelas (parameternya tidak opsional di kelas sehingga Anda dapat panggil metode tanpa itu), dan di tangan kedua ketika Anda mengimplementasikan antarmuka Anda harus mengikuti aturan antarmuka, sehingga Anda dapat mengganti metode dengan / tanpa parameter opsional. Hanya sebuah opini.
Mohamad Alhamoud
2
Lebih detail penjelasan masalah di sini -> geekswithblogs.net/BlackRabbitCoder/archive/2010/06/17/…
Andrew Orsich

Jawaban:

236

UPDATE: Pertanyaan ini adalah topik blog saya pada 12 Mei 2011. Terima kasih atas pertanyaannya!

Misalkan Anda memiliki antarmuka seperti yang Anda gambarkan, dan seratus kelas yang mengimplementasikannya. Kemudian Anda memutuskan untuk membuat salah satu parameter dari salah satu metode antarmuka menjadi opsional. Apakah Anda menyarankan bahwa hal yang benar untuk dilakukan adalah kompilator memaksa pengembang untuk menemukan setiap implementasi metode antarmuka itu, dan menjadikan parameter opsional juga?

Misalkan kita melakukan itu. Sekarang anggap pengembang tidak memiliki kode sumber untuk implementasi:


// 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

Bagaimana seharusnya penulis D membuat karya ini? Apakah mereka diharuskan di dunia Anda untuk memanggil pembuat B di telepon dan meminta mereka mengirimkan versi B yang baru yang membuat metode ini memiliki parameter opsional?

Itu tidak akan terbang. Bagaimana jika dua orang memanggil penulis B, dan salah satu dari mereka ingin defaultnya benar dan salah satunya ingin itu salah? Bagaimana jika penulis B menolak untuk ikut bermain?

Mungkin dalam kasus itu mereka akan diminta untuk mengatakan:

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

Fitur yang diusulkan tampaknya menambah banyak ketidaknyamanan bagi programmer tanpa peningkatan yang sesuai dalam kekuatan representatif. Apa manfaat menarik dari fitur ini yang membenarkan peningkatan biaya bagi pengguna?


UPDATE: Dalam komentar di bawah ini, supercat menyarankan fitur bahasa yang benar-benar akan menambah daya ke bahasa dan mengaktifkan beberapa skenario yang mirip dengan yang dijelaskan dalam pertanyaan ini. FYI, fitur itu - implementasi standar metode dalam antarmuka - akan ditambahkan ke C # 8.

Eric Lippert
sumber
9
@supercat: Kami tidak memiliki rencana untuk melakukannya, tetapi fitur seperti itu dimungkinkan. Sudah diusulkan sebelumnya. Selama proses desain untuk C # 4 kami melakukan banyak hal yang kami sebut fitur "ekstensi semuanya" - kami memiliki metode ekstensi, jadi apa artinya memiliki acara ekstensi, properti ekstensi, konstruktor ekstensi, antarmuka ekstensi, dan sebagainya . Kelas yang bisa Anda "lampirkan" ke antarmuka dan katakan "metode ini adalah implementasi standar antarmuka ini" adalah salah satu cara yang mungkin untuk mengkarakterisasi "antarmuka ekstensi". Ide yang menarik.
Eric Lippert
16
untuk memperjelas alasan saya mengapa saya pikir ini tidak intuitif: bagi saya parameter opsional adalah "opsional untuk pemanggil metode" TIDAK "opsional untuk pelaksana antarmuka".
Stefan de Kok
8
"Apakah mereka diwajibkan di duniamu untuk memanggil penulis B di telepon dan meminta mereka mengirimkan versi baru [...]?" Tidak, tidak perlu panggilan telepon. B seharusnya tidak lagi dianggap sebagai implementasi dari MyInterface dan penulis D dapat dibuat sadar akan hal itu oleh kompiler. Penulis D akan diminta untuk mengimplementasikan D dengan Metode Testm yang menerima parameter default karena itulah yang diperlukan oleh penulis Antarmuka - Anda berdebat menentang mengizinkan penulis antarmuka untuk menegakkan batasan karena seseorang mungkin ingin memecahkannya. Itu bukan argumen yang bagus.
philofinfinitejest
7
@EricLippert Dalam kasus di mana parameter opsional ditentukan untuk kenyamanan pengkodean, ya, menegakkan ketidaknyamanan dalam implementasi adalah kontra-intuitif. Tetapi dalam kasus di mana parameter opsional digunakan untuk meminimalkan overloading metode, fitur yang kuat, nilai-nilai opsional dapat mengambil signifikansi besar dan mengabaikannya tentu saja melemahkan kekuatan itu. Belum lagi kasus di mana implementasi konkret menentukan nilai default yang berbeda dari antarmuka. Sepertinya pemutusan sangat aneh untuk memungkinkan.
philofinfinitejest
8
Saya setuju dengan @philofinfinitejest di sini. Antarmuka memberi tahu apa yang dapat dilakukan sesuatu. Jika saya melewati implementasi antarmuka dengan nilai default yang berbeda dari yang ditentukan antarmuka, bagaimana saya tahu itu? Hei, saya memiliki antarmuka yang melewati true sebagai default, jadi mengapa hal ini menjadi salah? Itu, sepertinya saya TIDAK mendapatkan antarmuka yang saya harapkan. Lebih buruk lagi, saya sekarang harus memprogram untuk implementasi dan bukan antarmuka.
aaronburro
47

Parameter opsional baru saja ditandai dengan atribut. Atribut ini memberi tahu kompiler untuk memasukkan nilai default untuk parameter itu di situs panggilan.

Panggilan obj2.TestMethod();diganti dengan obj2.TestMethod(false);ketika kode C # dikompilasi ke IL, dan bukan pada waktu JIT.

Jadi dengan cara itu selalu penelepon memberikan nilai default dengan parameter opsional. Ini juga memiliki konsekuensi pada versi biner: Jika Anda mengubah nilai default tetapi tidak mengkompilasi ulang kode panggilan itu akan terus menggunakan nilai default lama.

Di sisi lain, pemutusan ini berarti Anda tidak bisa selalu menggunakan kelas konkret dan antarmuka secara bergantian.

Anda sudah tidak dapat melakukan itu jika metode antarmuka diterapkan secara eksplisit .

CodesInChaos
sumber
1
Bisakah Anda memaksa pelaksana untuk mengimplementasikan secara eksplisit?
naksir
30

Karena parameter default diselesaikan pada waktu kompilasi, bukan runtime. Jadi nilai default bukan milik objek yang dipanggil, tetapi ke tipe referensi yang dipanggil.

Olhovsky
sumber
7

Parameter opsional seperti substitusi makro dari yang saya mengerti. Mereka tidak benar-benar opsional dari sudut pandang metode. Artefak dari itu adalah perilaku yang Anda lihat di mana Anda mendapatkan hasil yang berbeda jika Anda menggunakan antarmuka.

Ariel Arjona
sumber