Autor |
Beitrag |
Määx
      
Beiträge: 123
|
Verfasst: Di 26.03.13 16:23
Hallo zusammen,
ich benötige für meine anwendung diverse Listen, die ich mir aus einer Datenbank hole. Da ich nicht jedesmal für die gleichen Inhalte eine Serveranfrage tätigen möchte, würde ich ddie Listen gerne global definieren. So etwas existiert in C# ja aber laut google nicht?
Ich habe jetzt angefangem das ganze mit einer sealed class zu machen. Aber irgendwie kommt mir das zu "kompliziert" für meinen Zweck vor. So habe ich es jetzt gelöst:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51:
| public sealed class Globals { private static volatile Globals instance; private static object syncRoot = new Object(); private static DateTime _lastUpdate; private static List<town> _towns; private static List<car> _cars; [...] private Globals() { _towns= Webservices.getTowns(); _cars = Webservices.getCars(); _lastUpdate = DateTime.Now; }
public static Globals Instance { get { if (instance == null) { lock (syncRoot) { if (instance == null) instance = new Globals(); } }
return instance; } } public static DateTime lastUpdate { get { return _lastUpdate; } } public static List<town> towns { get { return _towns; } } public static List<car> cars { get { return _cars; } } public static void updateData() { _towns= Webservices.getTowns(); _cars = Webservices.getCars(); _lastUpdate = DateTime.Now; } } } |
Ist das tatsächlich der Weg den man gehen sollte um globale Variablen zu deklarieren oder gibt es da etwas anderes, einfachereres?
Viele Grüße und vielen Dank
Määx
|
|
Ralf Jansen
      
Beiträge: 4708
Erhaltene Danke: 991
VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
|
Verfasst: Di 26.03.13 17:44
Eine statische Klasse wäre die simpelste Methode etwas ~global~ verfügbar zu machen. Und wie der Begriff simpel schon andeutet funktioniert das aber auch nur in den einfachsten Fällen. Genauso wie globale Variablen. Da würdest du auch irgendwann mit den Gedanken anfangen wie sind die nun absolut Global oder Thread Global und wenn die absolut Global sind was ist wenn ich doch mehrere Threads habe die drauf zugreifen. Ist das dann Threadsicher?
Um deine letzte Frage zu beantworten. Einfacher geht nicht. Nur besser.
|
|
Määx 
      
Beiträge: 123
|
Verfasst: Di 26.03.13 18:06
ok, danke für die schnelle Antwort!
Wie macht man es den besser  Wenn es keine globalen Variablen gibt und man es eh auf "Umwegen" machen muss, bin ich natürlich an einer möglichst guten Lösung interessiert. Threadsicher wäre natürlich wünschenswert...
Viele Grüße
Määx
|
|
Ralf Jansen
      
Beiträge: 4708
Erhaltene Danke: 991
VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
|
Verfasst: Di 26.03.13 18:46
Je nach Anforderung Service Locator, Inversion of Control, Dependency Injection oder andere Factory Patterns.
|
|
Määx 
      
Beiträge: 123
|
Verfasst: Do 28.03.13 15:22
Hey,
danke für das Feedback. Ich bin jetzt allerdings mit den ganzen Factorys etwas überfordert, da sich hierdurch ja ganze neue Möglichkeiten ergeben, so dass ich mein Konstrukt eigentllich ganz gerne anpassen würde.
Entsprechend muss ich an einer anderen Stelle ansetzen:
Mein System soll später folgendes machen: Man hat im Prinzip ein TabControl, dass es ermöglichen soll verschiedene Buchungen zu bearbeiten. Es gibt entsprechend in meiner MainForm ein Dictonary<int,Buchung>, das die möglichen Tabs wiederspiegelt.
Im Hintergrund läuft ein MSMQ-Thread, der bei einkommenden Messages diese via Eventing an die MainForm übergibt und dort den jeweiligen Eintrag aktualisiert bzw. einen neuen Eintrag & Tabpage erzeugt.
Jeder TabPage wird bei seiner Erzeugung eine Referenz auf das im Dictonary eingetragene Objekt Buchung übergeben und an die auf der TabPage befindlichen UserControls weitergereicht. Ändere ich nun über die UserControls Eigenschaften der Buchung soll in einem Hintergrundthread die Änderung wieder an den Server übertragen werden. Für die Serverkommunikation soll es -je nach Verfügbarkeit- verschiedene Möglichkeiten geben: SOAP, Messaging oder direkter Zugriff auf die lokale Datenbank. Hier habe ich mir überlegt etwas entsprechend der Factorys einzusetzen: Ich habe ein Interface ICom erstellt, dass die benötigten Funktionalitäten beschreibt und habe dann für jede Kommunikationsmethode entsprechend eine Klasse angelegt. Hierbei wird neben dem Ergebnis immer auch zurückgegeben, ob die Kommunikation erfolgreich war. Nun habe ich bei der weiteren Umsetzung mehrere Probleme, wie ich das konzeptionell am besten lösen könnte. Für eine Factory müsste ich jetzt ja eine statische Klasse schreiben, die z.B. die Funktion public static ICom getCommunication besitzt und dann dort prüfen, ob eine Verbindung verfügbar ist und entsprechend ein Objekt der Kommunikationsklasse zurückgeben.
Jetzt müsste ich bei der Verwendung dieser Klass ejedoch jedesmal prüfen, ob die Verbindung noch besteht und bei Fehlern die public static ICom getCommunication erneut aufrufen um eine alternative Verbindung zu erhalten.
Also wäre es ja sinnvoller eine Klasse Communication zu erstellen, die die gleiche Funktionalität wie ICom besitzt, jedoch keine Rückgabewerte über den Erfolg einer Verbindung aufweist, sondern bei einer Anfrage die verschiedenen ICom-Implementierungen durchgeht und dann wenn zB bekannt ist, dass SOAP nicht zur Verfügung steht sich dies merkt und zunächst die anderen Varianten prüft.
Ich bräuchte also -wenn ich das richtig sehe- ein globales Kommunikations-Objekt, dass den aktuellen Verbindungsstatus kennt und entsprechend bei jeder Anfrage einen Thread öffnet, der die entsprechende Kommunikation durchführt.
Wenn ich dazu in der MainFrame ein Objekt communication anlege und dieses ebenfalls bis zu den UserControlls durchreiche, kommt es mir irgendwie nicht sauber vor und ich vermute, dass es zu Problemen führen wird, die ich noch nicht abschätzen kann.
Wie siehst du das? Welchen Ansatz würdest du in meinem Fall verfolgen?
Vielen herzlichen Dank für die Hilfe!
Määx
|
|
Ralf Jansen
      
Beiträge: 4708
Erhaltene Danke: 991
VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
|
Verfasst: Do 28.03.13 16:42
Zitat: | Jetzt müsste ich bei der Verwendung dieser Klass ejedoch jedesmal prüfen, ob die Verbindung noch besteht und bei Fehlern die public static ICom getCommunication erneut aufrufen um eine alternative Verbindung zu erhalten. |
Wieso mußt du das? Kann die Klasse das nicht selbst lösen ohne den Nutzer der Klasse damit zu belasten?
Zitat: | Also wäre es ja sinnvoller eine Klasse Communication zu erstellen, die die gleiche Funktionalität wie ICom besitzt, jedoch keine Rückgabewerte über den Erfolg einer Verbindung aufweist, sondern bei einer Anfrage die verschiedenen ICom-Implementierungen durchgeht und dann wenn zB bekannt ist, dass SOAP nicht zur Verfügung steht sich dies merkt und zunächst die anderen Varianten prüft. |
Das wäre eine Art von Factory. Ich könnte mir aber auch vorstellen das es auch nur ein weiterer Implementor von ICom ist der halt die anderen Varianten ~wiederverwendet~. Letztlich wäre das Interface doch das gleiche und auch wenn er verschiedene Methoden durchprobiert können immer noch alle scheitern. Das Fehlerverhalten wäre also auch bei einer solchen Klasse meiner Meinung nach das gleiche.
Zitat: | Ich bräuchte also -wenn ich das richtig sehe- ein globales Kommunikations-Objekt, dass den aktuellen Verbindungsstatus kennt und entsprechend bei jeder Anfrage einen Thread öffnet, der die entsprechende Kommunikation durchführt. |
Warum global warum nicht einfach als innerer Status deiner Kommunikationsklasse? Ich weiß nicht warum du einen Verbindungstatus brauchst aber ich würde eher zum Neuaufbauen einer Verbindung tendieren. Wenn der Aufbauaufwand zu hoch dann würde ich auch eher einen Verbindungspool Ansatz wählen in den ich benutzte aber (zumindest scheinbar) funktionierende Verbindungsobjekte poole bis sie jemand anderes braucht.
|
|
Määx 
      
Beiträge: 123
|
Verfasst: Do 28.03.13 17:35
Hey,
stimmt... falls alle Verbindungen scheitern sollten, muss ich das ja auch behandeln. Ich könnte das also tatsächlich als weiteren Implementator verwenden.
Zitat: | Warum global warum nicht einfach als innerer Status deiner Kommunikationsklasse? |
Naja ich dachte ja an eine globale Kommunikationsklasse, die sich merkt, dass z.B. der Messaging-Dienst nicht erreichbar ist und somit garnicht erst probiert eine Nachricht zu versenden und somit das ganze zu beschleunigen. Aber stimmt, dass kann ich ja auch jeweils als inneren Status regeln. Im schlimmsten Fall würde das dann ja bedeuten, dass bei einer weiteren Instanz ein Verbindungsversuch getätigt wird. Aber eigentlich kann ich es auch jedes mal probieren, da dies ja eh in einem Thread geschieht und somit sichergestellt wird, dass Messaging verwendet wird, sobald der Server wieder verfügbar ist...
Dann könnte ich ja auch die gesamte Kommunikationsklasse als static definieren und direkt mit Communication.updateBuchung( myBuchung ) in einem BackgroundWorker ausführen und bei einem Fehler eine Rückmeldung an die GUI geben, oder?
Vielen Dank!!
|
|
|