Bagaimana cara menerapkan metode statis pada antarmuka?

92

Saya memiliki C ++ DLL pihak ketiga yang saya panggil dari C #.

Metodenya statis.

Saya ingin mengabstraksikannya untuk melakukan beberapa pengujian unit jadi saya membuat antarmuka dengan metode statis di dalamnya tetapi sekarang program saya mengalami kesalahan dengan:

Pengubah 'statis' tidak valid untuk item ini

MyMethod cannot be accessed with an instance reference; qualify it with a type name instead

Bagaimana saya bisa mencapai abstraksi ini?

Kode saya terlihat seperti ini

private IInterfaceWithStaticMethods MyInterface;

public MyClass(IInterfaceWithStaticMethods myInterface)
{
  this.MyInterface = myInterface;
}

public void MyMethod()
{
  MyInterface.StaticMethod();
}
Jon
sumber
3
Mungkin Anda dapat melakukannya dengan metode ekstensi: stackoverflow.com/questions/1243921/…
hcb

Jawaban:

47

Anda tidak dapat menentukan anggota statis pada antarmuka di C #. Antarmuka adalah kontrak untuk contoh .

Saya akan merekomendasikan membuat antarmuka seperti Anda saat ini, tetapi tanpa kata kunci statis. Kemudian buat kelas StaticIInterfaceyang mengimplementasikan antarmuka dan memanggil metode C ++ statis. Untuk melakukan pengujian unit, buat kelas lain FakeIInterface, yang juga mengimplementasikan antarmuka, tetapi melakukan apa yang Anda perlukan untuk menangani pengujian unit Anda.

Setelah Anda menentukan 2 kelas ini, Anda dapat membuat kelas yang Anda perlukan untuk lingkungan Anda, dan meneruskannya ke MyClasskonstruktor.

davisoa
sumber
65
-1 untuk mengatakan An interface is a contract, not an implementation.- itu benar, tetapi sama sekali tidak relevan ( non sequitur ) di sini, karena metode statis bukan bagian dari implementasi itu sendiri - implementasi, menurut definisi, didasarkan pada data , yang, pada gilirannya, tidak dapat diakses untuk anggota statis. An interface type definition can define and implement static methods (see §8.4.3) since static methods are associated with the interface type itself rather than with any value of the type.- ingatlah bahwa staticanggota biasanya merupakan metode utilitas .
2
Saya mengerti dan setuju dengan pernyataan Anda, dan saya merasa komentar Anda adalah konteks yang penting juga. Meskipun. saat mendesain antarmuka, orang harus menganggapnya sebagai kontrak, yang berarti metode statis tidak berlaku. Saya pikir saya harus membiarkannya di sana untuk membantu beberapa orang memahami tujuan antarmuka. Apakah komunitas merasa itu harus dihapus?
davisoa
1
Saya setuju sebagian bahwa An interface is a contract, not an implementationitu tidak berguna, terkadang sedikit kontekstualisasi sangat membantu. Dan saya sangat setuju dengan static method is not a part of implementation itself , metode statis memiliki implementasi, mereka menjadi bagian dari implementasi hanya jika digunakan sebagai implementasi dalam implementasi metode lain. Bagaimanapun kamus saya didasarkan pada apa yang dipelajari, setahu saya, terminologi sangat bervariasi juga tergantung pada bahasa pemrograman. Metode statis tidak dapat menjadi antarmuka karena hanya ada 1 implementasi.
CoffeDeveloper
Bayangkan saya memiliki IPersonkontrak yang menyatakan bahwa GetCountryakan memberikan nama negara asal orang tersebut ... FrenchPersonsemua entitas akan mengatakan "Prancis" dan GermanPersonsemua akan mengatakan "Jerman", juga berguna ketika berbagai jenis entitas memiliki Tabel (Data) yang sama, seperti MS Azure satu, katakanlah Connection, Postdan Commentdisimpan di UsersAzureTable, sehingga entitas pohon memiliki info bersama, IUsersdapat memiliki GetTableNamemetode statis ...
Serge
@vaxquis - IMHO, "its a contract" akan relevan jika kalimatnya diubah: `Antarmuka adalah kontrak untuk contoh . Anggota statis adalah bagian dari tipe; Kalimat yang disusun ulang ini mengatakan (dengan benar) bahwa mereka tidak ada artinya dalam kontrak instance. Jadi menurut saya masalahnya hanyalah kata-kata yang tidak tepat, bukan non sequitur.
ToolmakerSteve
112

Antarmuka tidak boleh memiliki anggota statis dan metode statis tidak dapat digunakan sebagai implementasi metode antarmuka.

Yang dapat Anda lakukan adalah menggunakan implementasi antarmuka eksplisit:

public interface IMyInterface
{
    void MyMethod();
}

public class MyClass : IMyInterface
{
    static void MyMethod()
    {
    }

    void IMyInterface.MyMethod()
    {
        MyClass.MyMethod();
    }
}

Alternatifnya, Anda dapat dengan mudah menggunakan metode non-statis, bahkan jika mereka tidak mengakses anggota khusus instance.

Danny Varod
sumber
18
Bagi siapa pun yang bertanya-tanya mengapa ada orang yang ingin melakukan ini, ini sangat berguna saat menulis pengujian unit / integrasi untuk kode lama yang mengimplementasikan metode statis.
Dezzamondo
Teknik ini bekerja dengan sangat baik untuk mengimplementasikan RESTful API cepat yang diperlukan untuk menyimpan data tetapi tidak bisa menggunakan database. Implementasinya hanya bekerja dengan objek C # dalam memori sehingga tidak ada tempat untuk menyimpan data, tetapi menggunakan properti statis dapat mengurangi kebutuhan database dalam memori menggunakan EF Core atau SQLite.
gware
19

Anggota statis benar-benar legal di CLR, hanya saja bukan C #.

Anda dapat menerapkan beberapa perekat di IL untuk menghubungkan detail implementasi.

Tidak yakin apakah kompilator C # akan mengizinkan pemanggilan mereka?

Lihat: 8.9.4 Definisi tipe antarmuka ECMA-335.

Jenis antarmuka harus tidak lengkap karena mereka tidak mengatakan apa-apa tentang representasi nilai dari jenis antarmuka. Untuk alasan ini, definisi tipe antarmuka tidak boleh memberikan definisi field untuk nilai tipe antarmuka (misalnya field instance), meskipun ia dapat mendeklarasikan field statis (lihat §8.4.3).

Demikian pula, definisi tipe antarmuka tidak boleh menyediakan implementasi untuk metode apa pun pada nilai tipenya. Namun, definisi tipe antarmuka dapat — dan biasanya memang — menentukan kontrak metode (nama metode dan tanda tangan metode) yang akan diimplementasikan oleh tipe pendukung. Definisi tipe antarmuka dapat mendefinisikan dan mengimplementasikan metode statis (lihat §8.4.3) karena metode statis dikaitkan dengan tipe antarmuka itu sendiri daripada dengan nilai tipe apa pun.

leppie
sumber
10
Sebagai referensi, CLS Rule 19: CLS-compliant interfaces shall not define static methods, nor shall they define fields.selanjutnya dikatakan bahwa tidak masalah bagi konsumen yang patuh CLS untuk menolak jenis antarmuka ini. Saya mencoba sekitar setahun yang lalu untuk memanggil metode statis pada sebuah antarmuka dan kompiler C # tidak akan mengkompilasinya.
Christopher Currens
Lebih jauh ke catatan @ChristopherCurrens tentang CLS: Common Language Specification (CLS) is a set of basic language features that .Net Languages needed.... When there is a situation to communicate Objects written in different .Net Complaint languages , those objects must expose the features that are common to all the languages. Masuk akal bahwa jika CLS adalah tentang interoperabilitas di berbagai bahasa .NET, dan C # tidak mengizinkan anggota statis pada antarmuka, maka CLS akan melarang mereka juga, untuk memastikan perpustakaan di bahasa .NET lainnya dapat dipanggil dari C #.
Simon Tewsi
17

Anda dapat mendefinisikan metode statis di c # 8 tetapi Anda harus mendeklarasikan isi default untuk itu.

    public interface IMyInterface
    {
          static string GetHello() =>  "Default Hello from interface" ;
          static void WriteWorld() => Console.WriteLine("Writing World from interface");
    }

atau jika Anda tidak ingin memiliki isi default, cukup berikan pengecualian:

    public interface IMyInterface
    {
          static string GetHello() =>  throw new NotImplementedException() ;
          static void WriteWorld() => throw new NotImplementedException();
    }
AliReza
sumber
Sepertinya anggota statis dalam antarmuka sangat tidak berguna karena Anda tidak dapat mengaksesnya dengan contoh antarmuka. Setidaknya di C # 8.
Pavel Sapehin
3
sebagai sudut pandang implementasi Antarmuka, hak Anda. itu tidak berguna. tetapi dengan cara ini setidaknya Anda yakin memiliki metode yang diimplementasikan pada setiap kelas yang menggunakan antarmuka ini. (ini adalah jenis implementasi opsional untuk antarmuka)
AliReza
5

Anda bisa memintanya dengan refleksi:

MyInterface.GetType().InvokeMember("StaticMethod", BindingFlags.Static | BindingFlags.Public | BindingFlags.InvokeMethod, null, null, null);
John Koerner
sumber
5
Dan jika Anda tidak memiliki instance MyInterface, Anda dapat menggunakan "typeOf (MyInterface)" daripada "myInterface.GetType ()".
RenniePet
Sepertinya ide yang bagus pada saat itu, dan saya dapat terus melakukannya melalui refleksi, tetapi satu peringatan kecil: itu menjadi lebih bermasalah jika program dikaburkan sedemikian rupa sehingga metode StaticMethod diganti namanya.
RenniePet
1
@RenniePet: Anda dapat menangani sebagian penggantian nama StaticMethod dengan menggunakan nameof (StaticMethod) sebagai gantinya. Ini BISA membantu dengan obfuscator tergantung pada bagaimana itu mengganti nama. Jika Anda melakukannya dengan cara ini, Anda setidaknya akan melihat kesalahan waktu kompilasi.
Brent Rittenhouse
Refleksi terlalu ekstrim untuk kasus ini
Stepan Ivanenko
3

C # "Sepuluh" akan mengizinkan anggota statis pada antarmuka , bersama dengan peran. Ini adalah langkah maju yang besar, ini akan memungkinkan operator generik kelebihan beban juga, tanpa menggunakan refleksi. Berikut ini cuplikan contoh cara kerjanya, menggunakan contoh monoid klasik, yang hanya jargon untuk mengatakan "sesuatu yang bisa ditambahkan". Diambil langsung dari Mads Torgersen: C # into the Future :

interface IMonoid<T>
{
    static T Zero { get; }
    static T operator +(T t1, T t2);
}

public static T AddAll<T>(T[] ts) where T : IMonoid<T>
{
    T result = T.Zero;
    foreach (T t in ts) { result += t; }
    return result;
}

role IntAddMonoid extends int : IMonoid<int>
{
    public static int Zero => 0;
}

IntAddMonoid[] values = new int[] {1, 2, 4, 8, 16, 32};
int sixtyThree = AddAll<IntAddMonoid>(values); // == 63

Sumber daya tambahan:

Jeremy Bytes: C # 8 antarmuka anggota statis

EDIT

Posting ini awalnya menyatakan antarmuka anggota statis akan ditambahkan di C # 8.0 , yang tidak benar, saya salah menafsirkan kata-kata Mads Torgersen dalam video. Panduan resmi C # 8.0 belum berbicara tentang anggota antarmuka statis, tetapi jelas mereka telah mengerjakannya cukup lama sekarang.

Tamas Hegedus
sumber
1

Tentang mengapa Anda tidak dapat memiliki metode statis pada antarmuka: Mengapa C # Tidak Mengizinkan Metode Statis untuk Menerapkan Antarmuka?

Namun, saya menyarankan untuk menghapus metode statis demi metode instance. Jika itu tidak memungkinkan, Anda dapat menggabungkan panggilan metode statis di dalam metode instance, lalu Anda dapat membuat antarmuka untuk itu dan menjalankan pengujian unit dari itu.

yaitu

public static class MyStaticClass
{
    public static void MyStaticMethod()
    {...}
}

public interface IStaticWrapper
{
    void MyMethod();
}

public class MyClass : IStaticWrapper
{
    public void MyMethod()
    {
        MyStaticClass.MyStaticMethod();
    }
}
Justin Pihony
sumber
apa keuntungan menggunakan antarmuka dengan kelas statis dibandingkan hanya menggunakan antarmuka?
Selen
1

C # 8 Memungkinkan Anggota Statis di Antarmuka

Dimulai dengan C # 8.0, sebuah antarmuka dapat menentukan implementasi default untuk anggota. Ini juga dapat menentukan anggota statis untuk menyediakan implementasi tunggal untuk fungsionalitas umum.

antarmuka (Referensi C #)

Misalnya

public interface IGetSomething
{
    public static string Something = "something";
}

var something = IGetSomething.Something;
Christian Findlay
sumber