Laden...

Interface durch statische Klasse implementieren

Erstellt von Gremgiz vor 13 Jahren Letzter Beitrag vor 13 Jahren 5.780 Views
G
Gremgiz Themenstarter:in
106 Beiträge seit 2006
vor 13 Jahren
Interface durch statische Klasse implementieren

Hallo,

ich habe eine Frage zur Nutzung von Interfaces. Ich möchte ein Interface erstellen, um Programmmeldungen auszugeben.

Das Interface:


namespace Interfaces
public interface IMessages
{
   byte ShowMessage (int ID, byte ButtonCount, byte Level, string[] Text);
}

Die eigentliche Methode zur Ausgabe


using Interfaces;
namespace Core
public class Message
{
   public static byte ShowMessage(int ID, byte ButtonCount, byte Level, string[] Text)
   {
      //Anzeige, Auswertung und Rückgabe
   }
}

Beispielhafte Anwendung des Interfaces


using Interfaces
namespace Addresses
public class Suche : IMessages
{
   // Interface Implementierung
   public byte ShowMessage(int ID, byte ButtonCount, byte Level, string[] Text)
   {
       return ShowMessage(ID, ButtonCount, Level, Text
   }

   //irgendeine Methode
   public static void DoSomething()
   {
      //...commands...

      ShowMessage(177,1,1,null);

      //...further commands...
   }

Dabei kommen zwei Fehler:> Fehlermeldung:

  1. Addresses.Suche implementiert den Schnittstellenmeber Interface.IMessage.ShowMessage nicht. Ist statisch und kann daher keinen Schnittstellenmember implementieren.

  2. Für das für das nicht statische Feld, Eigenschaft oder Methode "Addresses.DoSomething.ShowMessage(int, byte, byte, string[])" ein Objektverweis erforderlich wäre. Wie soll der denn aussehen? Oder habe ich einen generellen Denkfehler drin?

Kann man in statischen Klassen keine Interfaces implementieren?

S
753 Beiträge seit 2006
vor 13 Jahren

Hallo,
laut Doku Interfaces (C# Programming Guide) können Interfaces kein static in der Definition haben, und deine Klasse Suche muss die folgende Methode Implementieren:


  byte IMessages.ShowMessage(int ID, byte ButtonCount, byte Level, string[] Text)
      {
         return dein call;
      }

Die statische Methode ist keine Implementierung des Interfaces, weil die Signatur falsch ist.


public static byte ShowMessage(int ID, byte ButtonCount, byte Level, string[] Text)

ist nicht gleich

byte IMessages.ShowMessage(int ID, byte ButtonCount, byte Level, string[] Text)

Life is a short

G
Gremgiz Themenstarter:in
106 Beiträge seit 2006
vor 13 Jahren

Das mit "return dein call" verstehe ich jetzt nicht ganz.

  
  byte IMessages.ShowMessage(int ID, byte ButtonCount, byte Level, string[] Text)  
      {  
         return dein call;  
      }  

wie kann ich aus der Klasse Suche jetzt direkt darauf zugreifen? Ich babe die Methode nun wie folgt implementiert:


public byte IMessage.ShowMessage(int ID, byte ButtonCount, byte Level  string[] Text)
{
   //wie aufrufen?
}

Ich kann nicht auf IMessage.ShowCustomer direkt zugreifen und nur ShowCustomer kennt diese Klasse ja nicht, da Sie woanders definiert ist.

1.552 Beiträge seit 2010
vor 13 Jahren

Hallo Gremgiz

IMessages mess = new Suche();
mess.ShowMessage(....);

Suche search = new Suche();
search.ShowMessage(....);

Gruß
Michael

Mein Blog
Meine WPF-Druckbibliothek: auf Wordpress, myCSharp

849 Beiträge seit 2006
vor 13 Jahren

der 2. Aufruf wird so nicht klappen weil er es explicit implementiert hat. gewünscht?

public byte IMessage.ShowMessage(int ID, byte ButtonCount, byte Level  string[] Text)  
{  
   //wie aufrufen?  
}  

Das wird auch so nicht klappen, weil hier eine explicite impl. public gesetzt wurde.

1.552 Beiträge seit 2010
vor 13 Jahren

es explicit implementiert hat. gewünscht

Da gibt es mehrere Möglichkeiten:


public  void DoSomething()
{
    (this as IMessages).ShowMessage(177, 1, 1, null);
}
//bzw
public  void DoSomething()
{
    IMessages mess = this;
    mess .ShowMessage()
}

Mein Blog
Meine WPF-Druckbibliothek: auf Wordpress, myCSharp

G
Gremgiz Themenstarter:in
106 Beiträge seit 2006
vor 13 Jahren

Hallo,

ja die strikte Trennung ist gewünscht. Ich skizziere mal kurz wie das ganze, um dass es hier exemplarisch get, aussieht. Es gibt ein Modul Adressen, dass sich um die Suche und Darstellung von Adressen kümmert. Weiterhin gibt es ein Modul Core, das alle Funktionen beinhaltet, die generell benötigt werden. Dazu zählt u.a. die Ausgabe von Programmmeldungen, die typischerweise an verschiedenen Stellen (Modulen) benötigt wird. Das Interface, das beide Welten zusammenbringen soll, liegt momentan in einem weiteren Namespace. Hier kann man sicherlich überlegen, ob die vom Core behandelten Interfaces im gleichen Namespace liegen sollten. Momentan liegen sie in einem eigenen Namespace. Ich habe also jetzt 3 Namespaces:

  • Adressen
  • Core
  • Interface

Erreichen möchte ich, dass die Adressensuche meinetwegen sagen will, dass die Adresse nicht vorhanden ist. Es übergibt also die benötigten Daten für die Ausgabe an das Interface. Das Interface soll nun die Methode aufrufen, die sich um die Ausgabe sämtlicher Programmmeldungen kümmert, das Ergebnis der Meldung entgegennehmen (als Byte Zahl) und dies der eigentlich aufrufenden Methode zurückgeben.

Bisher wurde das übner statische Methoden realisiert, aber im Zuge eines Refactoring soll dies geändert werden, so das austauschbare Module entstehen.

Hier nochmal der aktuelle Code, der nach den Hinweise (danke dafür) entsprechend umgesetzt wurde:

  1. Interface

namespace Interfaces
{
    public interface IMessages
    {
        byte ShowMessage(int ID, byte ButtonCount, byte Level, string[] Text);
    }
}

  1. Aufrufendes Adressmodul

using Interfaces;

namespace Addresses
{
    public class presAddress_SearchCustomer : IMessages
    {
        byte IMessages.ShowMessage(int ID, byte ButtonCount, byte Level, string[] Text)
        {
            IMessages mess = new presAddress_SearchCustomer();
            return mess.ShowMessage(ID, ButtonCount, Level, Text);
        }

        public static void GetCustomer()
        {
            if (keine Kunden gefunden)
            {
                ShowMessage(177, 1, 1, null); //Der Aufruf klappt so nicht
            }
        }
    }
}

  1. Die Auswertende Methode zur Ausgabe

using Interfaces;

namespace Core
{
    public class presCore_Message : IMessages
    {
        public byte ShowMessage(int ID, byte ButtonCount, byte Level, string[] Text)
        {
            //Ausgbe und Auswertung
            return Rückgabewert;
        }
     }
}

Gruß
Gremgiz

1.552 Beiträge seit 2010
vor 13 Jahren
public static void GetCustomer()  
{  
   if (keine Kunden gefunden)  
   {  
      ShowMessage(177, 1, 1, null); //Der Aufruf klappt so nicht  
   }  
}  

Ja der Aufruf klappt aus dem Grund nicht da deine Methode static ist.
Wieso dann eine Get[...] void als Rückgabewert hat verstehe ich auch nicht. Wahrscheinlich um temporär den Code zum kompilieren zu bringen.

Mein Blog
Meine WPF-Druckbibliothek: auf Wordpress, myCSharp

49.485 Beiträge seit 2005
vor 13 Jahren

Hallo Gremgiz,

es gibt weder statische Interfaces noch kann eine statische Klasse ein Interface implementieren. Wurde alles schon ausführlich besprochen.

Das Design ist ohnehin ungünstig. Du kannst dein Problem lösen, in dem du das Design änderst. Es ist nicht die Aufgabe der Module, Nachrichten auszugeben, sondern das gehört ins GUI. Mach es also besser so:

public static List <Customer> GetCustomer()
{
   if (keine Kunden gefunden) {
      return null;
   }
}

var list = GetCustomer();
if (list == null || list.Count == 0) {
   ShowMessage(177, 1, 1, null);
}

Mach ShowMessage zu einer Methode der GUI-Klasse und du kannst dir das Interface sparen. Wenn das GUI ausgetauscht werden soll, schreibt man im neuen GUI die Methode neu oder auch eine andere Methode und alles passt wieder, denn die Methode wird von GUI definiert und nur im GUI benutzt.

herbivore

5.742 Beiträge seit 2007
vor 13 Jahren

Mach es also besser so

Ohne das jetzt weiter vertiefen zu wollen, sollte man hier IMHO lieber schreiben:


if (keine Kunden gefunden) {
   return new List<Customer>();
}

null als Rückgabewert ist häufig sehr ungünstig, da man ihn zusätzlich prüfen muss. Eine leere Liste hingegen kann man im G){gray}runde wie eine volle behandeln ohne, dass man unangenehme Nebeneffekte hat.

Hinweis von herbivore vor 13 Jahren

Ich hatte befürchtet, dass der Einwand kommt. Im realen Programm würde man es doch sowieso ganz anders machen. Da würde man doch die (leere) Liste ganz am Anfang erzeugen und dann würde man in der DB oder wo auch immer suchen und aus den Ergebnissen die Liste füllen und wenn man dabei keine Treffer hat, dann würde die Liste eben leer bleiben und am Ende würde man die Liste (unabhängig von der Anzahl der Elemente, also ganz ohne eine if-Abfrage) zurückgegeben (return list;). Diese Struktur wäre aber schwer darstellbar gewesen und ich wollte außerdem die Struktur des vorgegebenen Beispiels möglichst wenig ändern. Deshalb und nur deshalb ist mein Beispiel so wie es ist. Im realen Programm würde man also weder return null; noch return new List<Customer>(); schreiben. Es ist eben nur ein Beispiel, dessen Fokus auf der Trennung von GUI und Modell lag und nicht auf der konkreten Rückgabe.

G
Gremgiz Themenstarter:in
106 Beiträge seit 2006
vor 13 Jahren

Hallo,

vielen Dank für die wertvolle Hilfe von Euch.

es gibt weder statische Interfaces noch kann eine statische Klasse ein Interface implementieren. Wurde alles schon ausführlich besprochen.

Ja, das musste ich dann wohl auch einsehen...

Das Design ist ohnehin ungünstig. Du kannst dein Problem lösen, in dem du das Design änderst. Es ist nicht die Aufgabe der Module, Nachrichten auszugeben, sondern das gehört ins GUI.

Genau da liegt der Aufruf schon. Das geht nur aus den Codeschnipseln nicht so hervor. Die Anzeige, dass keine Adressen gefunden sind beherbergt noch eine Option zu einer anderen Suchmethode, die aber nur auf Wunsch angestoßen werden soll. Die eigentliche Ausgabe der Meldung befindet sich im natürlich ebenfalls GUI, jedoch an einer zentralen Stelle. Der hier gepostete Code ist nur ein Teil eines größeren Moduls, dass an den Rumpf angedockt wird. Das Modul selber bildet auch alle benötigten Schichten ab.

Ich bin aber auf einem gutem Wege es hinzubekommen.

Gruß
Gremgiz

G
Gremgiz Themenstarter:in
106 Beiträge seit 2006
vor 13 Jahren

Hallo nochmal,

ich denke, dass ich das Prinzip eines Interfaces nicht richtig verstanden habe. Daher werden auch meine Probleme mit der Handhabung herühren. Ich möchte daher einmal einen mehr theoretischen Ansatz mit Euch diskutieren.

Nehmen wir einmal an es gibbt ein Programm, das auch vielen Modulen besteht und eine zentrale Instanz, die sagen wir als Verwalter dient. Die einzelnen Module sind komplett autark und beliebig austauschbar. Eines dieser Module möchte nun eine Meldung ausgeben. Darum kümmert isch wiederum ein Modul. Nun hatte ich das so verstanden, dass das Interface eine Art Agent ist, der die Anfrage entgegen nimmt und nachsieht wohin es damit soll. Damit wäre das in der zentralen Logik angesiedelt. Sich einen solchen Agenten selbst zu schreiben ist kein Problem, da es auch nur einen Methodenaufruf darstellt. Dau könnte man sich auch Klassen definieren, um für jede Eventualität gerüstet zu sein. Bisher dachte ich, dass ein Interface genau so ein Agent ist, der mir die Arbeit abnimmt, aber scheinbar ist es nicht so?

Nun etwas praktischer: Das Modul, dass die Meldung ausgeben will, spricht also das Interface an und übergibt die benötigten Parameter (in meinem Fall als Methodenaufruf). Nach den Hinweise in diesem Thread muss ich aber jetzt schon auf den Teil refrenzieren, der das Interface behandelt und genau dass ist es was ich nicht will.

Kann mir jemand ein kleines Beispiel geben wie es funktioniert? Ich stelle mir das so vor, dass Modul A an ein Interface Daten übergibt und vom Interface die Rückgabe erhält. Das Interface und nur dieses soll wissen, was mit den Daten zu tun ist und diese entsprechend verarbeiten - in dem Fall Modul B aufrufen, um die Meldung auszugeben.

Natürlich kann man das ganze ohne Interface machen, ich verspreche mir aber etwas mehr Übersichtlichkeit davon, es mit INterface zu machen.

Danke und viele Grüße
Gremgiz

656 Beiträge seit 2008
vor 13 Jahren

Was du beschreibst wird oft durch einen zentralen Vermittler gelöst, der allen Komponenten bekannt ist - den sogenannten Mediator.

Wie das ganze jetzt konkret implementiert ist, hängt von den Anforderungen ab.
Bei dir könnte die zentrale Stelle im einfachsten Fall selber der Mediator sein, und beispielsweise eine ShowMessage Methode zur Verfügung stellen.
Die kann im wiederum einfachsten Fall ein Event auslösen, wo sich andere Module (die in der Lage sind, eine Message auszugeben) dranhängen können (oder auch nicht).

49.485 Beiträge seit 2005
vor 13 Jahren

Hallo Gremgiz,

Nehmen wir einmal an es gibbt ein Programm, das auch vielen Modulen besteht ...

vorneweg: Module klingt nicht sehr objektorientiert. Und wenn diese als statische Klassen realisiert sind, bestätigt das den Verdacht. Sprich besser darüber, welche Klassen und vor allem welche Objekte es gibt.

Eines dieser Module möchte nun eine Meldung ausgeben.

Wie ich schon versucht habe darzustellen, ist es nicht die Aufgabe der Module, Meldungen auszugeben. Module sollen ihre Arbeit verrichten und Ergebnisse liefen. Eventuell können sie zwischendurch noch Events werfen, um über bestimmte Zustandsänderungen oder Zwischenergebnisse zu informieren. Aber zu entscheiden, welche Meldungen bei welchen Ergebnissen (oder Ereignissen) ausgegeben werden, ist Sache des Guis. Aufrufe wie ShowMessage haben nichts in den Modulen zu suchen.

dass das Interface eine Art Agent ist, der die Anfrage entgegen nimmt und nachsieht wohin es damit soll.

Nein, nicht das Interface ist der Agent, sondern so ein Agent ist immer ein Objekt, der das Interface implementiert. Das Interface definiert eben - wie der Name schon sagt - nur die Schnittstelle.

Nach den Hinweise in diesem Thread muss ich aber jetzt schon auf den Teil refrenzieren, der das Interface behandelt und genau dass ist es was ich nicht will.

Nach meinen Hinweisen kannst du dir das schon sparen, weil meine Kernaussage ist, dass das Design gar nicht passt, du kein Interface und keinen Agenten brauchst, sondern es dem GUI überlässt, die Meldungen anzuzeigen und auch darüber zu entscheiden, wann welche Meldungen überhaupt angezeigt werden sollen.

Wenn du an anderer Stelle mal tatsächlich das Problem hast, ein Objekt (einen Agenten) zu erzeugen, damit zu es (ihn) über ein Interface ansprechen kannst, gibt es viele Lösungen, die aber alle unter dem Oberbegriff Dependency Injection laufen, d.h. dass natürlich nicht das Modul selbst entscheiden soll, welchen konkreten Agenten es benutzen soll, sondern dass diese Entscheidung nach außen verlagert wird, z.B. per Konstruktor/Parameter Injection, Property Injection oder über einen DI-Container.

herbivore