Laden...

Struct in einem Array von einem Singleton setzen und abfragen

Erstellt von piro299 vor 8 Jahren Letzter Beitrag vor 8 Jahren 6.418 Views
Thema geschlossen
P
piro299 Themenstarter:in
22 Beiträge seit 2016
vor 8 Jahren
Struct in einem Array von einem Singleton setzen und abfragen

Schönen guten Abend,

ich bin relativ neu mit C# unterwegs. Ich habe jahrelang Delphi (Pascal) programmiert und seit 2 Jahren Java.

Ich habe eine Klasse, die die Struktur meiner Daten hält.


namespace KECComputerMonitoring
{
    public struct SMemory
    {
        public string name;
        public string capacity;
        public string speed;
    }

    public sealed class AssetData
    {

        private SMemory[] memory;

        /* ############################################################## 
        */
        // Encapsulated instance - the single instance - thread-safe
        private static readonly AssetData instance = new AssetData();

        // Explicit static constructor to tell C# compiler not to mark type as beforefieldinit
        static AssetData() { }

        // Hide constructor
        private AssetData() { }

        // Return the single instance of this class.
        public static AssetData GetInstance { get { return instance; } }
        /* 
        ############################################################## */

        public SMemory[] Memory
        {
            get { return memory; }
            set { memory = value; }
        }
    }
}

Mit der Main Klasse hole ich mir jetzt die Instanz der Daten und ermittle mit WMI den Arbeitsspeicher.


namespace KECComputerMonitoring
{
    class Program
    {
        static void Main(string[] args)
        {

            AssetData assetData = AssetData.GetInstance;
            int idx;

            // Local WMI Request
            string computername = "localhost";
            ManagementScope scope = new ManagementScope("\\\\" + computername + "\\root\\cimv2");
            scope.Connect();

            ObjectQuery query = new ObjectQuery("Select * from Win32_PhysicalMemory");
            ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, query);
            assetData.Memory = new SMemory[searcher.Get().Count];
            idx = 0;
            foreach (ManagementObject obj in searcher.Get())
            {
                assetData.Memory[idx].name = obj["DeviceLocator"].ToString();
                assetData.Memory[idx].capacity = obj["Capacity"].ToString();
                assetData.Memory[idx].speed = obj["Speed"].ToString();
                idx++;
            }

            foreach (var obj in assetData.Memory)
            {
                Console.WriteLine(obj.name);
                Console.WriteLine(obj.capacity);
                Console.WriteLine(obj.speed);
                Console.WriteLine("");
            }
            Console.ReadLine();

        }
}

Mein Lösungsweg funktioniert. Nur würde ich gerne wissen, ob das der richtige Weg ist. Die Singleton Klasse ist ok. Aber die Daten abspeichern stelle ich in Frage.

Vielen Dank im Voraus für alle Anregungen oder Verbesserungsvorschläge.

Mfg
Sven

16.807 Beiträge seit 2008
vor 8 Jahren
  • Singletons ist zu 99,9999% bad practise
  • Man würde hier eine Klasse mit Eigenschaften verwenden, statt ein struct

Aber so richtig schlau, was Du da vor hast, bin ich nicht.
Im Prinzip - bei diesem Anwendungsfall - würde man eine einfache Liste nehmen.
Wenn es eher ne richtige Datenbank, aber nur sehr lokal sein soll, dann zB SQlite.

Warum willst Du denn ein Singleton?
Was ist denn überhaupt das Ziel?

P
piro299 Themenstarter:in
22 Beiträge seit 2016
vor 8 Jahren

Meine Anwendung ermittelt mit Hilfe von verschiedensten Klasse (WMI, Regitry und Dateisystem) die Daten eines Rechners. Um die ermittelten Daten temporär zu speichern, existiert die Datenklasse mit dem Singleton.
Dadurch muss ich das Daten Objekt nicht immer hin und her kopieren.
Wenn alle Datn ermittelt sind, werden sie in eine MS SQL Datenbank gespeichert.

Wie würde denn eine Alternative aussehen?

MFG

3.003 Beiträge seit 2006
vor 8 Jahren

Dein Datenobjekt wird in aller Regel sowieso nicht "hin und her kopiert", sondern ledliglich eine Referenz weitergegeben (das setzt voraus, dass man ein Objekt hat, und kein struct. Struct ist ausschließlich für das Organisieren von, wenn sie einmal erhoben sind, unveränderlichen Daten. Dein Fall ist ein Grenzfall - und wenn man darüber nachdenkt, ob struct oder class, dann sollte man die Finger von struct lassen). Das heisst, du bist sowieso sicher, dass es sich innerhalb einer Datenerhebung um ein und dasselbe Objekt handelt, selbst, wenn mal mehrere Thread parallel Daten sammeln sollten. Mit anderen Worten: Singleton ist hier nicht nur keine Hilfe, sondern behindert das saubere Zuordnen einer Aufgabe (Daten sammeln) von ihrem Ergebnis. Schönes Beispiel von Singleton als Antipattern.

Weiterhin sollte dir schon aufgefallen sein, dass dein Array erzwingt, dass du searcher.Get() mehrfach aufrufen musst, das erste Mal nur, um die Menge der Daten zu ermitteln. Das ist nicht nur ineffizient, sondern liefert unter Umständen (vielleicht nicht in deinem Fall, aber anderswo) verfälschte Daten.

Ich nenn' das mal Schrödinger's Code: wenn der Wert der Rückgabe nicht festgelegt ist, bevor man nicht mit Get() darauf zugreift, dann wird das erste Get() das Ergebnis festlegen, obwohl man das zu diesem Zeitpunkt noch gar nicht wollte. Hat man also eine Katze in einem Karton, weiss man nach dem ersten Hineinschauen, ob sie lebt oder tot ist. Das zweite Hineinschauen liefert dann dasselbe Ergebnis und ist damit direkt abhängig vom ersten, ein Effekt, der nicht gewollt ist.

Aus diesem Grund macht sich eine Liste an der Stelle, wie Abt gesagt hat, besser. Oder gleich eine eigens definierte Collection, so dass mehr Struktur in die Daten kommt, die du erhebst.

LaTino

"Furlow, is it always about money?"
"Is there anything else? I mean, how much sex can you have?"
"Don't know. I haven't maxed out yet."
(Furlow & Crichton, Farscape)

W
872 Beiträge seit 2005
vor 8 Jahren

Um mal zu Deinem eigentlichen Problem zurückzukommen:
Ich würde die Daten als JSON abspeichern.
Dafür würde ich eine Methode


string ToJson() 

und einen Instanzmethode

 static SMemory FromJson(string jsonString)

definieren.
Dafür würde ich dann Json.Net nehmen.
Ich würde auch im Regelfall mit Class und nicht mit Struct arbeiten.

3.003 Beiträge seit 2006
vor 8 Jahren

Um mal zu Deinem eigentlichen Problem zurückzukommen:
Ich würde die Daten als JSON abspeichern.

Aus Neugier: wie würdest du das begründen?

LaTino

"Furlow, is it always about money?"
"Is there anything else? I mean, how much sex can you have?"
"Don't know. I haven't maxed out yet."
(Furlow & Crichton, Farscape)

W
872 Beiträge seit 2005
vor 8 Jahren

JSON ist ein Standardformat zum Serialisieren. Handlicher und besser lesbar als XML.

3.003 Beiträge seit 2006
vor 8 Jahren

Das mag ja sein, aber wieso willst du dem Datenobjekt zusätzlich die Aufgabe geben, zu (de)serialisieren und dabei auch noch fix auf eine bestimmte Art der Serialisierung verdrahten? Was, wenn er die Daten in einer DB speichern will (SQLite wurde ja bereits vorgeschlagen)?


interface IMemoryDataProvider
{
     void Save(SMemory data);
     SMemory Load();
}

class Program
{
    static void Main()
    {
          //...
          IMemoryDataProvider dataProvider = new JsonProvider("example.json");
          foreach(var sMemory in mySMemoryList)
               dataProvider.Save(sMemory);

          dataProvider = new SqLiteProvider(dbConnectionString);
          foreach(var sMemory in mySMemoryList)
               dataProvider.Save(sMemory);

         //oder auch:
         dataProvider = new JsonProvider("savedData.json");
         var loadedData = dataProvider.Load();
         dataProvider = new SqLiteProvider(dbConnectionString);
         dataProvider.Save(loadedData);
    }
}

  • single responsibility: sMemory hält nur die Daten
  • Entkopplung: zur Laufzeit Änderung der Speichermethode möglich
  • Daten serialisiert speichern, ist nicht immer eine gute Idee. Abgesehen davon ist die Idee hinter JSON, Daten universell und personenlesbar austauschen zu können. Zum reinen Speichern kann man es sicher verwenden, aber dafür gibt es dann doch geeignetere Möglichkeiten.

Bisschen das Syndrom "Wenn man einen Hammer hält, sieht alles wie ein Nagel aus."

LaTino

"Furlow, is it always about money?"
"Is there anything else? I mean, how much sex can you have?"
"Don't know. I haven't maxed out yet."
(Furlow & Crichton, Farscape)

P
piro299 Themenstarter:in
22 Beiträge seit 2016
vor 8 Jahren

Moin,
Danke schon mal für die vielen Anregungen und Tipps.

Ich möchte gerne die Daten, die in den unterschiedlichen Klassen ermittelt werden zentral in meiner Anwendung Zwischenspeichern.

Wenn ich alles ermittelt habe, werden die Daten in eine MS SQL Datenbank gespeichert.

Ich die SingleInstance Klasse von Java und finde das Konzept gut. Deshalb die Idee mit der Singleton Klasse.

Die Daten temporär in eine json oder xml Datei zu speichern halte ich für zu viel.

Ist es denn so schlimm die Singleton Klasse zu verwenden, um zentral Daten in der Anwendung zu speichern? Gibt es noch andere Möglichkeiten?

Das mit List anstelle von Arrays und Klassen anstelle von Structs werden ich umsetzen.

Vielen Dank im Voraus.

Bin gespannt auf weitere Ideen oder Tipps.

Sven

16.807 Beiträge seit 2008
vor 8 Jahren

Warum hälst Du Dich nicht zB an [Artikel] Drei-Schichten-Architektur und speicherst es entsprechend in einer lokalen Variable an der richtigen Stelle?

Singleton ist kein guter Code.
Wenn Du das jetzt für gut erachtest, dann frag ich mich, warum wir Dir alternativen und den korrekten / besseren Weg vorschlagen, wenn es am Ende für Dich irrelevant ist..!?

3.003 Beiträge seit 2006
vor 8 Jahren

Ist es denn so schlimm die Singleton Klasse zu verwenden, um zentral Daten in der Anwendung zu speichern? Gibt es noch andere Möglichkeiten?

Beide Fragen wurden dir schon beantwortet. Wenn Singleton als Ersatz für globale Variablen benutzt wird, ist das der falsche Ansatz. Wieso, wurde auch schon beantwortet, Alternativen wurden genannt.

LaTino

"Furlow, is it always about money?"
"Is there anything else? I mean, how much sex can you have?"
"Don't know. I haven't maxed out yet."
(Furlow & Crichton, Farscape)

5.657 Beiträge seit 2006
vor 8 Jahren

Hi piro299,

das Singleton-Entwurfsmuster hat nichts mit der Programmiersprache zu tun, und wäre in deinem Anwendungsbeispiel auch in Java oder jeder anderen Sprache die falsche Herangehensweise. Wie soewas normalerweise umgesetzt wird, ist ja bereits gesagt worden. Abgesehen davon ist das Abfragen, Verarbeiten und Speichern von Daten Bestandteil (fast) jeder beliebigen Software. Da kannst du dir auch mal Code-Beispiele anschauen, die du im Netz findest, und dich davon inspirieren lassen. Oder dir mal ein Buch zu C# oder objektorientierter Programmierung durchlesen, z.B. das Openbook vom Rheinwerk-Verlag: 🛈

Da findest du dann auch Informationen zu den Unterschieden zwischen Wert- und Referenztypen und speziellen Datenstrukturen wie Dictionarys oder Listen.

Christian

Weeks of programming can save you hours of planning

P
piro299 Themenstarter:in
22 Beiträge seit 2016
vor 8 Jahren

danke schon mal.

Eure Vorschläge sind nicht irrelevant. Ich habe vorher nur in Delphi programmiert und da war OOP nicht so stark bis gar nicht erforderlich.

Versteht bitte mein mehrmaliges Fragen nicht als Ignoranz gegenüber euren Vorschlägen. Ich möchte es nur genau verstehen und das richtige Vorgehen lernen.

In Delphi habe ich mir globale Objekte gebaut, um die Daten zu halten. Ich finde aber die Idee mit den Klassen echt gut. So wird alles übersichtlicher. Nur verstehe ich noch nicht wie man am besten Daten zwischen Klassen austauscht, dass am Ende ein großer Datentopf rauskommt, mit dem man weiter arbeiten kann, w.z.B. die Daten in die DB zu speichern.

Also wären die Alternativen, die Daten als JSON zu speichern und dann mit einer Funktion wieder zu lesen und in die MS SQL Datenbank zu speichern.
Json.NET sieht ganz interessant aus.

Ich würde gerne eine Datenklasse ohne Singleton machen. Nur wie kann ich dann die ermittelten Daten zwischen den Klassen hin und her schieben, ohne immer neue Objekte zu erzeugen.

Danke für eure Hilfe.

Sven

16.807 Beiträge seit 2008
vor 8 Jahren

Mit Json hat das doch überhaupt nichts zutun.
Warum musst Du denn die Daten überhaupt längerfristig irgendwo speichern? Das hast Du bis jetzt nicht erklärt.

Du willst doch nur Daten abrufen und dann direkt in ein MSSQL Server übertragen.
Wo ist denn die Notwendigkeit, dass eine lokale Variable (eine Liste mit Objekten) in der Logik nicht ausreicht? Warum brauchst Du diesen "Datentopf"? 🤔

Daten sollten nur so kurz wie möglich gehalten werden. Egal ob in Delphi, Java oder C#.
Wenn Du den Singleton auch schon in Delphi hattest....da war wohl Dein Delphi Code auch nicht gerade "Lehrbuchhaft" 😉

Latino hat Dir bereits den entsprechenden Codeaufbau gezeigt.
Der erfüllt alle Anforderungen, die Du bisher hier genannt hast.

P
piro299 Themenstarter:in
22 Beiträge seit 2016
vor 8 Jahren

Sorry.

Ich möchte alles nur temporär speichern und ja zum Schluss in eine DB ablegen.

Meine Anwendung soll Daten hauptsächlich Daten aus WMI und der Registry ermitteln und in ein Datenobjekt speichern.

Deshalb meine Idee eine Klasse, die die Datenstruktur hat, eine Klasse, welche die WMI Daten ermittelt und eine Klasse, die die Registry Daten ermittelt.

Alles wir von der Main Methode aus gestartet.

Deshalb wollte ich Objekt aus meiner Datenklassen erzeugen und in die jeweiligen Klassen (WMI und Registry) übergeben. Nur kam ich nicht klar, wie ich die Daten zwischen den Klassen hin und her schiebe.
Deshalb ist die Idee, des Singleton entstanden, da wir das in einem größeren Java Projekt auch gemacht hatten.

Wenn die WMI und die Registry Klassem mit Ihren jeweiligen Funktionen die Daten in die Datenklasse gespeichert haben, kann ich mit einer weiteren Klasse dann die Daten in die MS SQL DB speichern.

Das ist die ganze Idee meines Programmes, welches derzeit super mit Delphi funktioniert. Halt nur nicht mit OOP.

Da ich von Delphi weg muss, habe ich mir C# ausgesucht und versuche meine Anwendung nachzubauen und gleich alles mit OOP zu machen.
Was ich als sehr großen Vorteil sehe.

Vielen Dank an alle.
Sven

P
piro299 Themenstarter:in
22 Beiträge seit 2016
vor 8 Jahren

Hier mal ein Beispiel, wie ich mir das eigentlich gedacht hatte.

Daten Klasse


public class Daten 
{
   public string ComputerName {get; set;}
   public stringDomain {get; set;}
   public Serial {get; set;}
   public ActiveDirectorySiteName {get; set;}

   // was mir fehlt ist noch ein Objekt für die Software (Name, installiert am) und der Arbeitsspeicher (Name, Größe und Speed)

   public Daten () // Konstruktor
   { ... }
}

WMI Klasse


public class WMI 
{
   // wie kann ich das Daten Objekt ansprechen, um weitere Variablen zu füllen?
   ...
   // WMI Abfragen in Bezug auf Serial, Domäne und und ...

   public GatheringData()
   {
   ...
   }
}

Registry Klasse


public class Registry
{
   // wie kann ich das Daten Objekt ansprechen, um weitere Variablen zu füllen?
   ...
   // Registry Abfragen in Bezug auf ActiveDirectory SiteName oder Software ...

   public GatheringData()
   {
   ...
   }
}

Daten in eine DB speichern Klasse


public class DB
{
   // wie kann ich das Daten Objekt ansprechen, um alle ermittelten Daten in eine DB zu speichern?
   public TransferData()
   {
   ...
   }
}

Hauptklasse (oder wie man die nennt)


class Program
{
   static void Main(string[] args)
   {
      Daten myData = new Daten();
      myData.ComputerName = Environment.GetEnvironmentVariable("COMPUTERNAME");

      WMI.GatheringData();      // wie übergebe ich myData sinnvoll?
      Registry.GatheringData(); // wie übergebe ich myData sinnvoll?
      DB.TransferData();        // wie übergebe ich myData sinvoll, so das alle ermittelten Daten vorhanden sind? 
   }
}

Es fehlen noch einige Konstruktoren in den Klassen aber es soll nur die Idee veranschaulichen.

Lasst mich gerne wissen, wenn ich einen falschen Weg gehe.

Danke.
Sven

4.931 Beiträge seit 2008
vor 8 Jahren

Hallo,

// wie kann ich das Daten Objekt ansprechen, um weitere Variablen zu füllen?

Übergib einfach eine Referenz der Daten an die entsprechenden Methoden:


public void GatheringData(Daten daten)
{
  var name = daten.ComputerName; // lesen
  daten.ComputerName = "MeinTollerRechner"; // schreiben
}

(alternativ direkt an den Konstruktor und speichern in einer Membervariablen)


// in Main
Daten myData = new Daten();

var wmi = new WMI();
wmi.GatheringData(myData);

var registry = new Registry()
registry.GatheringData(myData);

var db = new DB();
db.TransferData(myData);

Das ist der objektorientierte Weg 😉

P
piro299 Themenstarter:in
22 Beiträge seit 2016
vor 8 Jahren

Ah. Wo ich es jetzt sehen, habe ich immer ein Problem gemacht, wo keines ist.

Vielen Dank für das kleine Beispiel. Hat mich sehr weit voran gebracht und ich kann auf Singleton verzichten.

Jetzt bleibt nur noch die Frage, wie ich sinnvoll eine Struktur für die Software und den Arbeitsspeichern in meine Daten Klasse bekomme.

P
piro299 Themenstarter:in
22 Beiträge seit 2016
vor 8 Jahren

Moin,

leider habe ich gerade keine Windows Rechner hier. Erst Montag auf Arbeit aber was Th69 geschrieben hat, funktioniert doch nicht ganz, da es ein Call by Value bei der Übergabe der Daten in die Funktion ist.


// in Main
Daten myData = new Daten();

var wmi = new WMI();
wmi.GatheringData(myData); // => werden Daten in dieser Funktion gesetzt, kennt doch registry.GatheringData(myData) die Daten gar nicht, man müsste also die Daten wieder zurückgeben oder?

var registry = new Registry()
registry.GatheringData(myData);

var db = new DB();
db.TransferData(myData); // myData wäre doch leer, oder?

Sehe ich das richtig oder habe ich einen Gedankenfehler. Das war doch so.
Ich würde gerne bei den Funktionen einen bool Wert zurückgeben, um zu wissen, ob alles gut gegangen ist.

D
261 Beiträge seit 2015
vor 8 Jahren

Du übergibst deinen Methoden nur eine Referenz von "myData". (siehe auch MSDN - Verweistypen)
Du übergibst also nicht jedesmal alle Daten, sondern nur eine Adresse zu den Daten.
Das gilt nur für Verweistypen (s.o.) und nicht für Werttypen (MSDN - Werttypen)

Ich würde dir übrigens das c# openbook von Rheinwerk empfehlen. (Link ist hier links im Menü)

P
piro299 Themenstarter:in
22 Beiträge seit 2016
vor 8 Jahren

Ah ok. Das wusste ich nicht. Ich hatte damals(vor 10 Jahren) in C++ gelernt, dass man mit Pointer arbeiten muss, um die Referenz zu übergeben..
Deshalb sah es für mich wie ein Call by Value aus.

Habe es gerade auf meinem Windows Rechner testen können.
Das verändert ja alles. Das ist ja voll cool und erleichtert meine Programmierung um Welten.

Ist das erst seit C#?

Werde mir echt mal das Buch holen.

Vielen Dank an alle. Mein Problem ist gelöst. Jetzt weiß ich, wie ich es machen muss.

Schönes Wochenende an alle.
Sven

D
261 Beiträge seit 2015
vor 8 Jahren

Für Werttypen kannst du das Keyword "ref" verwenden um ein Call by Reference zu machen. (MSDN - ref
Hier noch ein Artikel für dich: [Artikel] Parameter-Übergabemechanismen: call by value vs. call by reference (ref/out)

Der komplette Inhalt des Buches ist übrigens kostenlos auf der Seite vom Rheinwerk Verlag einsehbar.

Was du mit "erst seit C#" meinst, weiß ich leider nicht.

5.657 Beiträge seit 2006
vor 8 Jahren

Das hat alles nichts mehr mit einem Code-Review zu tun. Hier geht es mittlerweile um die absoluten Grundlagen von C#, die man überall nachlesen kann. Bitte beachtet [Hinweis] Wie poste ich richtig?, Punkt 1.1, und Code-Review Regeln. Damit sich die Diskussion nicht weiter im Unendlichen verliert, hab ich den Thread jetzt geschlossen.

Christian

Weeks of programming can save you hours of planning

Thema geschlossen