Hmmm, eventuell mache ich gerade den zweiten Schritt vor dem ersten. Wie dem aber auch sei: Ich komme nicht weiter. Ich denke es ist mal wieder eine Kleinigkeit:
Es spielt dabei überhaupt keine Rolle, ob ich die Methode mit oder ohne Überlasung anlage / aufrufe und ob mit oder ohne "return;" Das Ergebnis ist immer gleich.
Also ich habe folgenden beispielhaften Code:
Erstmal die Klasse. Diese ist in eine eigene Klassendateiausgelagert.
SystemClass.cs
namespace SysteminventoryV2
{
class SystemClass
{
// Deklaration
// System
string? systemComputerName;
// Methode
public SystemClass(string systemComputerName) // Egal ob mit oder ohne Paramter
{
var searcher = new ManagementObjectSearcher("SELECT * FROM Win32_ComputerSystem");
using ManagementObjectCollection managementObjectCollection = searcher.Get();
ManagementObject? managementObject = managementObjectCollection.OfType<ManagementObject>().First();
this.systemComputerName = managementObject["Name"].ToString()?.ToLower() ?? "Default";
return; // Egal, ob mit oder ohne. Ergebnis immer gleich
}
}
Form1.cs
namespace SysteminventoryV2
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
SystemClass test = new SystemClass("Bla"); // Wenn in der Methode kein Parameter, dann lasse ich das natürlich hier leer)
lblSystemComputerName.Text = test.ToString();
}
}
}
So, dass nun nicht der Name des Computers steht ist mit dem Code ja erstmal logisch. Ich hätte aber zumindest mal erwartet, dass bei "lblSystemComputerName" das Wort "Bla" steht. Stattdessen steht da aber "SysteminventoryV2.SystemClass". Warum? Was läuft falsch?
Ich habe den Code auch immer wieder versucht anzupassen und natürlich mittels Variable an den Computernamen zu kommen, aber von Variablen will der Methodenaufruf überhaupt nichts wissen und gibt nur Fehler zurück.
Könnt ihr mir da bitte weiterhelfen?
Direkt auch die nächste Frage hinterher: Ist der Codeaufbau so überhaupt richtig oder gehe ich hier schon direkt einen falschen Weg? Wie sähe er richtig aus? Am Ende möchte ich ein Programm haben mit dem ich mir Informationen über den Computer anzeigen lassen kann.
Edit: Ergänzung und Rechtschreibfehler behoben.
IDE: Visual Studio 2022
Sofern nicht anders genannt basieren meine Projekte auf C# und .net 6
Bei test.ToString()
wird die Methode Object.ToString() aufgerufen, da du sie nicht in deiner Klasse (per override
) überschrieben hast - und standardmäßig wird der Typname zurückgegeben.
Besser ist es, du erstellst eine Eigenschaft (als Getter) für SystemComputerName
und benutzt diese dann.
So, mit der Angelegenheit befasst und zumindest das Ergebnis stimmt. Aber ist die Herangehensweise so auch richtig oder gibt es Einwände eurerseits?
Ich bin leider unsicher, bitte seht es mir nach, wenn ich öfters mal nachfrage. Ich denke aber es ist besser als es falsch verstanden zu haben und dann wieder umlernen zu müssen.
SystemClass.cs
namespace SysteminventoryV2
{
class SystemClass
{
// Deklaration
// System
public string? SystemComputerName { get; set; }
public string GetSystemComputername()
{
var searcher = new ManagementObjectSearcher("SELECT * FROM Win32_ComputerSystem");
using ManagementObjectCollection managementObjectCollection = searcher.Get();
ManagementObject? managementObject = managementObjectCollection.OfType<ManagementObject>().First();
this.SystemComputerName = managementObject["Name"].ToString()?.ToLower() ?? "Default";
return SystemComputerName;
}
public SystemClass() // Irgendwie bissel doof, dass das so leer jetzt ist, aber löschen kann man das ja scheinbar auch nicht.
{
}
}
}
Form1.cs
[...]
private void Form1_Load(object sender, EventArgs e)
{
SystemClass test = new SystemClass();
lblSystemComputerName.Text = test.GetSystemComputername();
}
IDE: Visual Studio 2022
Sofern nicht anders genannt basieren meine Projekte auf C# und .net 6
Du hast jetzt zwei verschiedene Design-Möglichkeiten vermischt.
In deinem erstem Code hast du im Konstruktor die Daten ermittelt, so daß du diese in einer Eigenschaft speichern solltest (der Setter sollte dabei private
sein, damit man den Text nicht von außen setzen kann, d.h. readonly):
public string? SystemComputerName { get; private set; }
public SystemClass()
{
// ...
SystemComputerName = ...;
}
// Aufruf
SystemClass test = new SystemClass();
lblSystemComputerName.Text = test.SystemComputername;
In deinem zweiten Code jetzt hast du dagegen eine eigene Methode erzeugt, so daß die Eigenschaft überflüssig ist (da der Wert direkt zurückgegeben wird).
Wenn du kein Klassenobjekt benötigst, dann kannst du auch die Methode (sowie die Klasse) statisch machen:
public static string GetSystemComputername()
{
string? systemComputerName = ...;
return systemComputerName;
}
Dann wird diese Methode direkt über den Klassennamen aufgerufen:
lblSystemComputerName.Text = SystemClass.GetSystemComputername();
Du mußt dir also designtechnisch überlegen, ob du die Werte nur einmalig ermitteln möchtest (und dann die Eigenschaften benutzt) oder aber ob jedesmal beim Aufruf die Werte abgefragt werden sollen. Es kommt dabei auch darauf an, ob du noch weitere Werte abfragen möchtest und du diese dann alle "im Rutsch" abfragst oder aber "lazy" nur die Methoden aufrufst, die in der konkreten Anwendung dann auch benötigt werden (die SystemClass
wäre dann also eine allgemeine Utility/Tool-Klasse und könnte in eine eigene Assembly [bzw. NuGet Package] ausgelagert werden).
Hallo und Frohes Neues,
ich habe die codetechnische Umsetzung leider nicht ganz verstanden.
Kannst du das anhand eines Beispiels bitte deutlicher machen? Und was ist in welcher Situation der bessere Ansatz?
Wie meinst du das mit dem Assembly? Das scheint sehr interessant zu sein. Vielleicht macht es Sinn auf diesem Ansatz auf zu bauen, weil dann könnte man das ja in anderen Projekten direkt wiederverwenden, oder?
Was die Wiederverwertbarkeit angeht brauche ich diesen Codefetzen nochmal:
var searcher = new ManagementObjectSearcher("SELECT * FROM Win32_ComputerSystem");
using ManagementObjectCollection managementObjectCollection = searcher.Get();
ManagementObject? managementObject = managementObjectCollection.OfType<ManagementObject>().First();
Damit kann ich dann zum Beispiel Hersteller und Typ ermitteln
Wo du aber das Thema "Design" ansprichst. Momentan sieht das Ganze noch so aus. Ich denke das ist nicht ganz richtig. Wenn das Programm mal Formen annimmt werden folgende Bestandteile enthalten sein:
IDE: Visual Studio 2022
Sofern nicht anders genannt basieren meine Projekte auf C# und .net 6
OK, codetechnische Umsetzung habe ich kapiert. (Hat etwas gedauert)
Die Frage bleibt aber, wann welche Vorgehensweise sinnvoller ist und ob meine Aufteilung sinnvoll ist.
Um es zu erklären.
In der Datei SystemClass.cs frage ich folgendes ab:
public string? SystemComputerName { get; private set; } public string? SystemOs { get; private set; } public string? SystemLastStart { get; private set; } public string? SystemOsCaption { get; private set; } public string? SystemOsDisplayVersion { get; private set; } public string? SystemLanIpAdress { get; private set; } public string? SystemDhcp { get; private set; } public string? SystemLastWindowsUpdate { get; private set; } public string? SystemOtherMicrosoftUpdates { get; private set; } public string? SystemSpaceCFree { get; private set; } public string? SystemBitlocker { get; private set; } public string? SystemBitockerKey { get; private set; } public string? SystemEnergySetting { get; private set; } public string? SystemWlanSsid { get; private set; } public string? SystemLastUser { get; private set; }
Daneben wird es aber noch andere Dateien geben, beispielsweise eine HardwareClass.cs und dort frage ich dann beispielsweise sowas hier ab:
public string? HardwareLocation { get; private set; } public string? HardwareManufactor { get; private set; } public string? HardwareModel { get; private set; } public string? HardwareType { get; private set; } public string? HardwareSerial { get; private set; } public string? HardwareBios { get; private set; } public string? HardwareCpu { get; private set; } public string? HardwareRamCapacity { get; private set; } public int? HardwareRamSlotsUsed { get; private set; } public int? HardwareRamSlotsAvailable { get; private set; } public string? HardwareMac { get; private set; } public string? HardwareDrive { get; private set; } public string? HardwareSpaceCAvailable { get; private set; } public string? HardwareBatteryCapacity { get; private set; }
IDE: Visual Studio 2022
Sofern nicht anders genannt basieren meine Projekte auf C# und .net 6
Wie schon geschrieben, kommt es darauf an, ob bei jedem Zugriff die Daten neu abgefragt werden sollen oder einmalig beim Erstellen des Klassenobjekts.
Einige der Werte können sich ja zur Laufzeit ändern (wie z.B. SystemSpaceCFree
), so daß du dies für dein Projekt selbst entscheiden mußt (oder du bietest beides an).
Du kannst dir auch z.B. mal WMIGatherer - A WMI wrapper and system information gatherer anschauen (bzw. übernehmen) sowie weitere unter GitHub: hardware-information projects.
Aber noch als Tipp:
Du solltest den WMI-Zugriff in einer eigenen (generischen) Methode (bzw. Klasse) implementieren, so wie es auch beim WMIGatherer in Wmi.cs ausgelagert ist (so daß du nicht jedesmal den Abfrage-Code kopieren mußt).