Bagaimana cara memperluas kelas dengan metode ekstensi c #?

98

Dapatkah metode ekstensi diterapkan ke kelas?

Misalnya, perpanjang DateTime untuk menyertakan metode Tomorrow () yang bisa dipanggil seperti:

DateTime.Tomorrow();

Saya tahu saya bisa menggunakan

static DateTime Tomorrow(this Datetime value) { //... }

Atau

public static MyClass {
  public static Tomorrow() { //... }
}

untuk mendapatkan hasil yang serupa, tetapi bagaimana cara memperpanjang DateTime sehingga saya dapat menjalankan DateTime.Tomorrow?

David Glenn
sumber

Jawaban:

70

Anda tidak dapat menambahkan metode ke tipe yang sudah ada kecuali tipe yang ada ditandai sebagai parsial, Anda hanya dapat menambahkan metode yang tampak seperti anggota tipe yang sudah ada melalui metode ekstensi. Karena ini kasusnya, Anda tidak dapat menambahkan metode statis ke tipe itu sendiri karena metode ekstensi menggunakan contoh dari tipe itu.

Tidak ada yang menghentikan Anda untuk membuat metode pembantu statis Anda sendiri seperti ini:

static class DateTimeHelper
{
    public static DateTime Tomorrow
    {
        get { return DateTime.Now.AddDays(1); }
    }
}

Yang akan Anda gunakan seperti ini:

DateTime tomorrow = DateTimeHelper.Tomorrow;
Andrew Hare
sumber
6
huh woot? kecuali jika diterapkan dalam waktu 6 bulan sejak saat ini dan jawaban Kumu di sana, ini terlihat tidak lengkap!
Cregox
4
@Cawas ini tidak lengkap, Andrew menunjukkan bagaimana melakukan ini dengan pembantu statis, bukan dengan metode ekstensi (karena tidak ada contoh).
Nick N.
1
Anda benar, Nick. Saya lebih suka metode ekstensi! ;)
cregox
2
Bagaimana dengan extensionmethod.net/csharp/datetime ? IMHO, sampel yang lebih baik untuk meminimalkan kurva pembelajaran adalah aplikasi nyata dengan kode sumber lengkap dan pola yang baik
Kiquenet
3
Masalah dengan kode ini adalah bahwa ini hanya berfungsi pada DateTime.Now dan bukan objek DateTime apa pun. Sebagai utilitas, seseorang mungkin ingin menggunakannya untuk menentukan hari setelah beberapa hari sebelumnya (atau yang akan datang). Belum lagi DateTime. Sekarang ditentukan setiap kali Anda menyebutnya ...
MintGrowth
181

Gunakan metode ekstensi .

Ex:

namespace ExtensionMethods
{
    public static class MyExtensionMethods
    {
        public static DateTime Tomorrow(this DateTime date)
        {
            return date.AddDays(1);
        }    
    }
}

Pemakaian:

DateTime.Now.Tomorrow();

atau

AnyObjectOfTypeDateTime.Tomorrow();
Kumu
sumber
2
Shuggy jawaban 's juga rusak beberapa lampu pada cara yang sama untuk memecahkan ini.
cregox
8
Jangan lupa 'menggunakan ExtensionMethods;' di bagian atas dokumen Anda untuk ini.
Luke Alderton
mengapa saya tidak bisa melakukan DateTime.Tomorrow ()?
lawphotog
Hai lawphotog, ekstensi ini membutuhkan objek, di sini DateTime adalah sebuah struct dan bukan sebuah objek.
Kumu
4
Seperti yang disebutkan dalam komentar sebelumnya (tampaknya tidak cukup jelas bagi saya), Anda TIDAK akan dapat menggunakan DateTime.Tomorrow()sebagai metode ekstensi hanya bekerja pada INSTANCES kelas dan struct kelas. Untuk "memperluas" metode statis pada struktur kelas, ikuti jawaban Andrew atau jawaban Shuggy .
Alex
18

Metode ekstensi adalah gula sintaksis untuk membuat metode statis yang parameter pertamanya adalah turunan dari tipe T terlihat seolah-olah merupakan metode turunan pada T.

Dengan demikian, manfaatnya sebagian besar hilang di mana Anda membuat 'metode ekstensi statis' karena mereka akan membingungkan pembaca kode bahkan lebih dari metode ekstensi (karena tampaknya sepenuhnya memenuhi syarat tetapi tidak benar-benar ditentukan di kelas itu) tanpa keuntungan sintaksis (mampu untuk menyambung panggilan dengan gaya fasih dalam Linq misalnya).

Karena Anda harus membawa ekstensi ke dalam ruang lingkup dengan menggunakan, saya berpendapat bahwa itu lebih sederhana dan lebih aman untuk dibuat:

public static class DateTimeUtils
{
    public static DateTime Tomorrow { get { ... } }
}

Dan kemudian gunakan ini di kode Anda melalui:

WriteLine("{0}", DateTimeUtils.Tomorrow)
ShuggyCoUk
sumber
11

Jawaban terdekat yang bisa saya dapatkan adalah dengan menambahkan metode ekstensi ke dalam System.Typeobjek. Tidak cantik, tapi tetap menarik.

public static class Foo
{
    public static void Bar()
    {
        var now = DateTime.Now;
        var tomorrow = typeof(DateTime).Tomorrow();
    }

    public static DateTime Tomorrow(this System.Type type)
    {
        if (type == typeof(DateTime)) {
            return DateTime.Now.AddDays(1);
        } else {
            throw new InvalidOperationException();
        }
    }
}

Jika tidak, IMO Andrew dan ShuggyCoUk memiliki implementasi yang lebih baik.

Adrian Godong
sumber
Ada masalah dengan pendekatan ini. Harus mengetik "typeof (...)" tidak nyaman, dan dengan Intellisense Anda akan melihat ekstensi dari setiap jenis. Tetap saja, itu pendekatan menarik yang belum pernah saya pikirkan, +1.
Meta-Knight
@ Meta-Knight Benar, itulah mengapa secara pribadi saya lebih suka jawaban orang lain. Jawaban saya akan memiliki sintaks yang paling dekat dengan pertanyaan OP, tetapi itu bukan cara terbaik untuk menyelesaikan masalah ini.
Adrian Godong
Typedapat diganti dengan jenis lain yang dibutuhkan. Saya menggunakannya dengan Fromdan berfungsi dengan sempurna. jadi saya kira jawaban ini umum tetapi benar
Katia
3

Saya akan melakukan hal yang sama seperti Kumu

namespace ExtensionMethods
{
    public static class MyExtensionMethods
    {
        public static DateTime Tomorrow(this DateTime date)
        {
           return date.AddDays(1);
        }    
    }
}

tapi sebut saja seperti ini DateTime (). Tomorrow () baru;

Pikirkan itu membuat lebih banyak dilihat daripada DateTime.Now.Tomorrow ();

mimo
sumber
1
Dan Anda melewatkan kesempatan untuk menulisnya sebagai komentar atas jawaban Kumu! : P
cregox
3

Mereka menyediakan kemampuan untuk memperluas tipe yang ada dengan menambahkan metode baru tanpa modifikasi yang diperlukan pada tipe. Memanggil metode dari objek berjenis diperpanjang dalam aplikasi menggunakan sintaks metode instance dikenal sebagai metode '' memperluas ''. Metode ekstensi bukan anggota instance pada tipe. Poin utama yang perlu diingat adalah bahwa metode ekstensi, yang didefinisikan sebagai metode statis, berada dalam cakupan hanya jika namespace secara eksplisit diimpor ke kode sumber aplikasi Anda melalui perintah using. Meskipun metode ekstensi didefinisikan sebagai metode statis, metode tersebut tetap dipanggil menggunakan sintaks instance.

Lihat contoh lengkapnya di sini http://www.dotnetreaders.com/articles/Extension_methods_in_C-sharp.net,Methods_in_C_-sharp/201

Contoh:

class Extension
    {
        static void Main(string[] args)
        {
            string s = "sudhakar";
            Console.WriteLine(s.GetWordCount());
            Console.ReadLine();
        }

    }
    public static class MyMathExtension
    {

        public static int GetWordCount(this System.String mystring)
        {
            return mystring.Length;
        }
    }
sudhakar
sumber
3

Saya sedang mencari sesuatu yang serupa - daftar kendala pada kelas yang menyediakan Metode Ekstensi. Tampaknya sulit untuk menemukan daftar yang ringkas jadi begini:

  1. Anda tidak dapat memiliki apa pun yang bersifat pribadi atau dilindungi - bidang, metode, dll.

  2. Ini harus menjadi kelas statis, seperti pada public static class....

  3. Hanya metode yang dapat berada di kelas, dan semuanya harus statis publik.

  4. Anda tidak dapat memiliki metode statis konvensional - metode yang tidak menyertakan argumen ini tidak diperbolehkan.

  5. Semua metode harus dimulai:

    public static ReturnType MethodName (ClassName ini _this, ...)

Jadi argumen pertama selalu merupakan referensi ini.

Ada masalah implisit yang ditimbulkannya - jika Anda menambahkan metode yang memerlukan kunci apa pun, Anda tidak dapat menyediakannya di tingkat kelas. Biasanya Anda akan memberikan kunci tingkat instance pribadi, tetapi tidak mungkin menambahkan bidang pribadi apa pun, meninggalkan Anda dengan beberapa opsi yang sangat canggung, seperti menyediakannya sebagai statis publik pada beberapa kelas luar, dll. Mendapat tidak pasti. Tanda - tanda bahasa C # memiliki desain yang agak buruk untuk ini .

Solusinya adalah dengan menggunakan kelas Metode Ekstensi Anda hanya sebagai Fasad ke kelas biasa, dan semua metode statis di kelas Ekstensi Anda hanya memanggil kelas yang sebenarnya, mungkin menggunakan Singleton .

Chris Moschini
sumber
2

Sayangnya, Anda tidak bisa melakukan itu. Saya yakin itu akan berguna. Lebih alami untuk mengetik:

DateTime.Tomorrow

dari:

DateTimeUtil.Tomorrow

Dengan kelas Util, Anda harus memeriksa keberadaan metode statis di dua kelas berbeda, bukan satu.

Meta-Knight
sumber
1

Jawaban kami telah kami perbaiki dengan penjelasan detail, sekarang lebih mudah untuk memahami metode ekstensi

Metode ekstensi : Ini adalah mekanisme di mana kita dapat memperluas perilaku kelas yang ada tanpa menggunakan subkelas atau memodifikasi atau mengkompilasi ulang kelas atau struct asli.

Kita dapat memperluas kelas khusus kita, kelas kerangka kerja .net dll.

Metode ekstensi sebenarnya adalah jenis metode statis khusus yang didefinisikan di kelas statis.

Karena DateTimekelas sudah diambil di atas dan karenanya kami belum mengambil kelas ini untuk penjelasannya.

Berikut contohnya

// Ini adalah kelas Kalkulator yang sudah ada yang hanya memiliki satu metode (Tambah)

public class Calculator 
{
    public double Add(double num1, double num2)
    {
        return num1 + num2;
    }

}

// Below is the extension class which have one extension method.  
public static class Extension
{
    // It is extension method and it's first parameter is a calculator class.It's behavior is going to extend. 
    public static double Division(this Calculator cal, double num1,double num2){
       return num1 / num2;
    }   
}

// We have tested the extension method below.        
class Program
{
    static void Main(string[] args)
    {
        Calculator cal = new Calculator();
        double add=cal.Add(10, 10);
        // It is a extension method in Calculator class.
        double add=cal.Division(100, 10)

    }
}
Sheo Dayal Singh
sumber