Wie kann ich statische Methoden auf einer Schnittstelle implementieren?

88

Ich habe eine C ++ - DLL eines Drittanbieters, die ich von C # aus aufrufe.

Die Methoden sind statisch.

Ich möchte es abstrahieren, um einige Unit-Tests durchzuführen, also habe ich eine Schnittstelle mit den darin enthaltenen statischen Methoden erstellt, aber jetzt sind meine Programmfehler mit:

Der Modifikator 'statisch' ist für dieses Element nicht gültig

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

Wie kann ich diese Abstraktion erreichen?

Mein Code sieht so aus

private IInterfaceWithStaticMethods MyInterface;

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

public void MyMethod()
{
  MyInterface.StaticMethod();
}
Jon
quelle
3
Vielleicht können Sie es mit Erweiterungsmethoden tun: stackoverflow.com/questions/1243921/…
hcb

Antworten:

45

Sie können keine statischen Elemente auf einer Schnittstelle in C # definieren. Eine Schnittstelle ist ein Vertrag für Instanzen .

Ich würde empfehlen, die Benutzeroberfläche so zu erstellen, wie Sie sie derzeit sind, jedoch ohne das statische Schlüsselwort. Erstellen Sie dann eine Klasse StaticIInterface, die die Schnittstelle implementiert und die statischen C ++ - Methoden aufruft. Um Unit-Tests FakeIInterfacedurchzuführen , erstellen Sie eine weitere Klasse , die ebenfalls die Schnittstelle implementiert, aber das tut, was Sie für Ihre Unit-Tests benötigen.

Sobald Sie diese beiden Klassen definiert haben, können Sie die für Ihre Umgebung benötigte erstellen und an MyClassden Konstruktor übergeben.

Davisoa
quelle
62
-1 für die Aussage An interface is a contract, not an implementation.- das ist wahr, aber völlig irrelevant ( keine Folge ), da die statische Methode nicht Teil der Implementierung selbst ist - die Implementierung basiert per Definition auf Daten , auf die wiederum für statische Mitglieder nicht zugegriffen werden kann. 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.- Bedenken Sie, dass staticMitglieder normalerweise Gebrauchsmethoden sind .
2
Ich verstehe Ihre Aussagen und stimme ihnen zu, und ich bin der Meinung, dass Ihr Kommentar auch ein wichtiger Kontext ist. Obwohl. Wenn man eine Schnittstelle entwirft, sollte man sie als Vertrag betrachten, was impliziert, dass statische Methoden nicht angewendet werden. Ich dachte, ich sollte es dort lassen, um einigen Leuten zu helfen, den Zweck einer Schnittstelle zu verstehen. Ist die Community der Meinung, dass es entfernt werden sollte?
Davisoa
1
Ich stimme teilweise zu, dass dies An interface is a contract, not an implementationnutzlos ist, manchmal hilft ein bisschen Kontextualisierung wirklich. Und ich stimme voll und ganz zu static method is not a part of implementation itself , statische Methoden haben eine Implementierung, sie werden nur dann Teil der Implementierung, wenn sie als Implementierung bei der Implementierung einer anderen Methode verwendet werden. Mein Wörterbuch basiert jedoch auf dem, was ich gelernt habe. Soweit ich weiß, variiert die Terminologie auch je nach Programmiersprache. Statische Methoden können keine Schnittstellen sein, da es ohnehin nur eine Implementierung geben kann.
CoffeDeveloper
Stellen Sie sich vor, ich habe einen IPersonVertrag, der besagt, GetCountrydass der Name des Herkunftslandes der Person angegeben wird ... FrenchPersonUnternehmen sagen alle "Frankreich" und GermanPersonalle "Deutschland", was auch nützlich ist, wenn verschiedene Arten von Unternehmen dieselbe (Daten-) Tabelle wie MS verwenden Azure eins, sagen wir Connection, Postund Commentwerden in der UsersAzureTable gespeichert , so dass Baumentitäten eine gemeinsame Information haben, IUserskönnte GetTableNamestatische Methode haben ...
Serge
@vaxquis - IMHO, "es ist ein Vertrag" wäre relevant, wenn der Satz umformuliert würde: `Eine Schnittstelle ist ein Vertrag für Instanzen . Statische Elemente sind Teil des Typs. Dieser umformulierte Satz besagt (richtig), dass sie in einem Instanzvertrag keine Bedeutung haben. Ich denke, das Problem ist nur eine ungenaue Formulierung, keine Nicht-Sequenzierung.
ToolmakerSteve
108

Schnittstellen können keine statischen Elemente haben und statische Methoden können nicht als Implementierung von Schnittstellenmethoden verwendet werden.

Sie können eine explizite Schnittstellenimplementierung verwenden:

public interface IMyInterface
{
    void MyMethod();
}

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

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

Alternativ können Sie einfach nicht statische Methoden verwenden, auch wenn diese nicht auf instanzspezifische Mitglieder zugreifen.

Danny Varod
quelle
17
Für alle, die sich fragen, warum jemand dies tun möchte, ist es besonders nützlich, wenn Sie Unit- / Integrationstests für Legacy-Code schreiben, der statische Methoden implementiert.
Dezzamondo
19

Statische Mitglieder sind in der CLR vollkommen legal, nur nicht C #.

Sie können etwas Kleber in IL implementieren, um die Implementierungsdetails zu verknüpfen.

Sie sind sich nicht sicher, ob der C # -Compiler das Aufrufen zulassen würde?

Siehe: 8.9.4 Definition des Schnittstellentyps ECMA-335.

Schnittstellentypen sind notwendigerweise unvollständig, da sie nichts über die Darstellung der Werte des Schnittstellentyps aussagen. Aus diesem Grund darf eine Schnittstellentypdefinition keine Felddefinitionen für Werte des Schnittstellentyps (dh Instanzfelder) enthalten, obwohl sie statische Felder deklarieren kann (siehe §8.4.3).

Ebenso darf eine Schnittstellentypdefinition keine Implementierungen für Methoden zu den Werten ihres Typs bereitstellen. Eine Schnittstellentypdefinition kann jedoch Methodenverträge (Methodenname und Methodensignatur) definieren, die von unterstützenden Typen implementiert werden sollen. Eine Schnittstellentypdefinition kann statische Methoden definieren und implementieren (siehe §8.4.3), da statische Methoden eher dem Schnittstellentyp selbst als einem beliebigen Wert des Typs zugeordnet sind.

Leppie
quelle
10
Als Referenz heißt CLS Rule 19: CLS-compliant interfaces shall not define static methods, nor shall they define fields.es weiter, dass es für CLS-konforme Verbraucher in Ordnung ist, diese Art von Schnittstellen abzulehnen. Ich habe vor ungefähr einem Jahr versucht, eine statische Methode für eine Schnittstelle aufzurufen, und der C # -Compiler hat sie nicht kompiliert.
Christopher Currens
Weiter zu @ChristopherCurrens Hinweis zum 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. Wenn es beim CLS um Interoperabilität zwischen verschiedenen .NET-Sprachen geht und C # keine statischen Mitglieder auf einer Schnittstelle zulässt, würde das CLS diese ebenfalls verbieten, um sicherzustellen, dass Bibliotheken vorhanden sind Andere .NET-Sprachen können von C # aus aufgerufen werden.
Simon Tewsi
14

Sie können statische Methoden in c # 8 definieren, müssen jedoch einen Standardtext dafür deklarieren.

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

oder wenn Sie keinen Standardkörper haben möchten, lösen Sie einfach eine Ausnahme aus:

    public interface IMyInterface
    {
          static string GetHello() =>  throw new NotImplementedException() ;
          static void WriteWorld() => throw new NotImplementedException();
    }
AliReza
quelle
Es scheint, dass statische Elemente in Schnittstellen ziemlich nutzlos sind, da Sie nicht über die Schnittstelleninstanz darauf zugreifen können. Zumindest in C # 8.
Pavel Sapehin
3
aus Sicht der Schnittstellenimplementierung Ihr Recht. es ist nutzlos. Auf diese Weise haben Sie jedoch sicher eine implementierte Methode für jede Klasse, die diese Schnittstelle verwendet. (Dies ist eine Art optionale Implementierung für Schnittstellen)
AliReza
5

Sie könnten es mit Nachdenken aufrufen:

MyInterface.GetType().InvokeMember("StaticMethod", BindingFlags.Static | BindingFlags.Public | BindingFlags.InvokeMethod, null, null, null);
John Koerner
quelle
5
Und wenn Sie keine Instanz von MyInterface haben, können Sie "typeOf (MyInterface)" anstelle von "myInterface.GetType ()" verwenden.
RenniePet
Es schien damals eine gute Idee zu sein, und ich kann es weiterhin durch Reflexion tun, aber eine kleine Warnung: Es wird problematischer, wenn das Programm so verschleiert wird, dass die Methode StaticMethod umbenannt wird.
RenniePet
1
@RenniePet: Sie könnten sich teilweise mit der Umbenennung von StaticMethod befassen, indem Sie stattdessen nameof (StaticMethod) verwenden. Es könnte mit einem Obfuscator helfen, je nachdem, wie es umbenannt wird. Wenn Sie dies auf diese Weise tun, wird zumindest ein Fehler bei der Kompilierung angezeigt.
Brent Rittenhouse
Reflexion ist zu extrem für diesen Fall
Stepan Ivanenko
3

C # "Ten" ermöglicht neben Rollen auch statische Elemente auf Schnittstellen . Dies ist ein großer Fortschritt, da auch eine generische Überlastung des Bedieners ohne Reflexion möglich ist. Hier ist ein Beispielausschnitt, wie es funktioniert, unter Verwendung des klassischen Monoid-Beispiels, das nur Jargon ist, um "etwas zu sagen, das hinzugefügt werden kann". Direkt aus Mads Torgersen: C # in die Zukunft 45:30 :

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

Zusätzliche Ressourcen:

Jeremy Bytes: Statische Mitglieder der C # 8-Schnittstelle

BEARBEITEN

Dieser Beitrag, in dem ursprünglich angegeben wurde, dass statische Mitglieder der Benutzeroberfläche in C # 8.0 hinzugefügt werden , was nicht stimmt. Ich habe Mads Torgersens Worte im Video falsch interpretiert. Der offizielle C # 8.0-Leitfaden spricht noch nicht über statische Schnittstellenmitglieder, aber es ist klar, dass sie schon ziemlich lange daran arbeiten.

Tamas Hegedus
quelle
1

Warum Sie keine statische Methode für eine Schnittstelle haben können: Warum erlaubt C # statischen Methoden nicht, eine Schnittstelle zu implementieren?

Ich würde jedoch vorschlagen, die statischen Methoden zugunsten von Instanzmethoden zu entfernen. Wenn dies nicht möglich ist, können Sie die statischen Methodenaufrufe in eine Instanzmethode einbinden. Anschließend können Sie eine Schnittstelle dafür erstellen und daraus Ihre Komponententests ausführen.

dh

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

public interface IStaticWrapper
{
    void MyMethod();
}

public class MyClass : IStaticWrapper
{
    public void MyMethod()
    {
        MyStaticClass.MyStaticMethod();
    }
}
Justin Pihony
quelle
Was ist der Vorteil der Verwendung einer Schnittstelle mit statischer Klasse gegenüber der Verwendung nur einer Schnittstelle?
Selen
0

C # 8 Ermöglicht statische Mitglieder auf Schnittstellen

Ab C # 8.0 kann eine Schnittstelle eine Standardimplementierung für Mitglieder definieren. Es kann auch statische Elemente definieren, um eine einzelne Implementierung für allgemeine Funktionen bereitzustellen.

Schnittstelle (C # Referenz)

Z.B

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

var something = IGetSomething.Something;
Christian Findlay
quelle