| Autor |
Beitrag |
Christian R.
Ehemaliges Mitglied
Erhaltene Danke: 1
|
Verfasst: Mi 25.02.09 14:18
Hallo.
Folgende Codeschnipsel.
program.cs
C#-Quelltext 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:
| using System; using System.Collections.Generic; using System.Linq; using System.Windows.Forms;
using AdDresser.Classes;
namespace AdDresser { static class Program { public static User User = new User();
[STAThread] static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new FormStartmenu()); } } } |
Classes/user.cs
C#-Quelltext 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:
| using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows.Forms;
namespace AdDresser.Classes { class User { public UserData.ConfigXml Config = new UserData.ConfigXml();
public String Username = "";
public User() { this.Username = "Default"; }
public String GetPath() { return Application.StartupPath + "/Save/" + this.Username; } } } |
Ich will folgendes erreichen:
Die User-Klasse soll nicht statisch sein. Die Instanz soll von überall aus abrufbar sein. Kein singleton, falls doch mal ein zweiter User gebraucht wird.
Daher die Entscheidung eine Eigenschaft User in Program zu implementieren. Aber der Typeninitialisierer stellt sich da quer. Ich würde gern wissen wieso.
Und mich interessiert außerdem, ob ich konzeptionell etwas ändern sollte. Mir fällt gerade keine bessere Lösung ein, als den User in Program zu registrieren.
|
|
JüTho
      
Beiträge: 2021
Erhaltene Danke: 6
Win XP Prof
C# 2.0 (#D für NET 2.0, dazu Firebird); früher Delphi 5 und Delphi 2005 Pro
|
Verfasst: Mi 25.02.09 14:34
Hallo,
zunächst bekommst Du laut SDK-Doku/MSDN durch InnerException die eigentliche Information zur TypeInitializationException (bitte künftig selbst nachlesen).
Ich vermute sehr stark, dass es nicht möglich ist, ein Objekt völlig identisch zu bezeichnen wie die Klasse: User ist in allen Fällen großgeschrieben. (Oder ist das nur ein Schreibfehler?) Siehe auch NET: Richtlinien für Namen.
Das statische User-Objekt kommt mir zumindest seltsam vor; aber ob das sinnvoll ist, will ich jetzt nicht beurteilen. Auf jeden Fall solltest Du zwischen Eigenschaften und lokalen Variablen trennen:
C#-Quelltext 1: 2: 3: 4: 5: 6: 7: 8:
| class User { private string username = "Default"; public String Username { get { return username; } set { username = value; } } } |
Übrigens wirst Du mit Deinem Pfad Probleme bekommen: Zumindest unter Vista hat ein normaler Benutzer im Anwendungsverzeichnis (und darunter) keine Schreibrechte, und unter Windows werden Verzeichnisse mit "\" gegliedert und nicht mit "/". Das "richtige" Verzeichnis ist unter Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) zu finden.
Gruß Jürgen
|
|
Christian R.
Ehemaliges Mitglied
Erhaltene Danke: 1
|
Verfasst: Mi 25.02.09 14:44
OK. Dann wohl erst einmal Hausaufgaben machen. Danke für den MSDN-Link.
|
|
Christian R.
Ehemaliges Mitglied
Erhaltene Danke: 1
|
Verfasst: Mi 04.03.09 17:21
Die MSDN hat mir nicht weitergeholfen. Die allgemeine Erklärung der TypeInitialzationException sagt nicht aus, was bei mir das Problem ist. Fakt ist schonmal: Am doppelten Bezeichner liegt es nicht, aber ich habe es vorsorglich trotzdem geändert, weil nachvollziehbar ist es ja.
Ich frage mal anders ...
Problemstellung:
Die User-Instanz soll global verwendbar sein. Da ich davon ausgehe, dass ich evtl. mal mehrere User-Instanzen gleichzeitig verwende, will ich die User-Klasse nicht als static deklarieren. Also fällt der Zugrif auf die Klasse direkt aus.
Da ich erst seit zwei Wochen mit C# arbeite, sind mir div. Konzepte noch unklar. "Ich denke oft Delphi 7." Nun habe ich für einen globalen Zugriff auf den angemeldeten Benutzer eine Instanz in "Program" anlegen wollen, was mir logisch erschien. So kann ich innerhalb jeder anderen Klasse auf den User mittels "Program.User" zugreifen.
Frage:
Ist das sinnvoll, was ich da tue? Wie erstelle ich alternativ eine globale Instanz eines Users, bzw. einer Klasse im Allgemeinen?
Ein kleiner Codeschnipsel wäre schon sehr hilfreich. Eine leere Klasse als Ersatz für User. Wo lege ich die Instanz der Klasse User global an? Ein Formular, welches auf die globale Instanz von User zugreift. Mehr will ich eigentlich nicht erreichen. Ich bin sonst nicht der Typ für "bitte Code posten", aber diesesmal wäre das eine große Hilfe für mich.
Danke, Christian
|
|
Ralf Jansen
      
Beiträge: 4708
Erhaltene Danke: 991
VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
|
Verfasst: Mi 04.03.09 17:40
| Zitat: | | Ist das sinnvoll, was ich da tue? Wie erstelle ich alternativ eine globale Instanz eines Users, bzw. einer Klasse im Allgemeinen? |
Verpass der User Klasse eine statische Methode (oder Property) die eine Instanz von sich selber liefert.
C#-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13:
| public class User { private static User _defaultInstance; public static User DefaultInstance { get { if (_defaultInstance != null) _defaultInstance = new User(); return _defaultInstance; } } } |
|
|
Christian R.
Ehemaliges Mitglied
Erhaltene Danke: 1
|
Verfasst: Mi 04.03.09 18:49
Ein Singleton mit öffentlichem Konstruktor. Ja, klar! Ich Depp. Ist zwar noch nicht die OptimalLösung, aber zumindest ein Anfang, um im Projekt weiterarbeiten zu können.
Aber ich möchte Dich noch korrigieren. Du überprüfst "Wenn Instanz vorhanden, dann neue Instanz erstellen." Sicher meintest Du "Wenn Instanz nicht vorhanden, dann neue Instanz erstellen."
Danke.
|
|
Ralf Jansen
      
Beiträge: 4708
Erhaltene Danke: 991
VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
|
Verfasst: Mi 04.03.09 18:56
| Zitat: | | Aber ich möchte Dich noch korrigieren. Du überprüfst "Wenn Instanz vorhanden, dann neue Instanz erstellen." Sicher meintest Du "Wenn Instanz nicht vorhanden, dann neue Instanz erstellen." |
Öh ... ja. Das war ...Öh .... Absicht. Genau. Ich wollte dich testen. Du hast bestanden 
|
|
Christian R.
Ehemaliges Mitglied
Erhaltene Danke: 1
|
Verfasst: Mi 04.03.09 19:05
JüTho hat folgendes geschrieben : | | Übrigens wirst Du mit Deinem Pfad Probleme bekommen: Zumindest unter Vista hat ein normaler Benutzer im Anwendungsverzeichnis (und darunter) keine Schreibrechte, ... Das "richtige" Verzeichnis ist unter Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) zu finden. |
Ok. Das Program soll Standalone und Portable werden. Wir speichern deshalb unter dem Anwendungsverzeichnis ab. Dein Hinweis ist berechtigt. Nun folgende Frage:
Ich verwende XP, bei mir klappt es wunderbar. Mein Mitprogrammierer nutzt Vista und Vista und dieses hat sich bisher nicht wegen fehlender Rechte beschwert. Zwar muss er diverse Anwendungen explizit als Administrator ausführen, aber bei unserem Programm klappt alles. Inwiefern könnten Probleme bei anderen Nutzern auftreten, bzw. wie kann man diese umgehen?
Danke.
|
|
Kha
      
Beiträge: 3803
Erhaltene Danke: 176
Arch Linux
Python, C, C++ (vim)
|
Verfasst: Mi 04.03.09 22:39
Wo lag denn das Programm? Im User-Verzeichnis, auf einem Stick, ... gibt es natürlich keine Probleme. Selbst in geschützten Verzeichnissen könnte Vistas Virtualisierung noch das Programm retten - die ist aber nur an, wenn das Programm kein Vista-Manifest eingebunden hat, welches VS08 normalerweise automatisch einträgt.
_________________ >λ=
|
|
Christian R.
Ehemaliges Mitglied
Erhaltene Danke: 1
|
Verfasst: Mi 04.03.09 23:41
Es war noch direkt in
Projekt/bin/Debug
Da die compilierte Executeable. Und in
Projekt/bin/Debug/Save
sind die Daten, auf die wir zugreifen. Diesen Ordner haben wir angelegt. Vielleicht deshalb? Weil er von uns erstellt wurde und damit die User-Rechte hat? Schade, dass ich mich mit Vista und dem Rechtemanagement nicht auskenne. Und auf meinem alten NB werde ich es bestimmt auch nicht aufspielen. Ich werde morgen mal ein paar Tests bei seinem Vista machen, um herauszufinden ob und wo es meckert.
PS: Er arbeitet nicht als Administrator, sondern als der Standard-User und eine "Project.vhost.exe.manifest" ist vorhanden.
Gute Nacht.
Edit:
Hätte ich fast vergessen.
JüTho hat folgendes geschrieben : | | ... und unter Windows werden Verzeichnisse mit "\" gegliedert und nicht mit "/". |
In Delphi hatte ich dieses Problem auch nie. Und bei PHP habe ich mir diese Schreibweise auch angewöhnt. Sonst müsste ich ständig die BackSlashes der lokalen Projekte in Slashes für meine Server-Projekte umändern.
Im Hinterkopf habe ich immer den Gedanken, dass mein Programm auch mal auf anderen OS laufen soll. Ich habe zwar keine Ahnung, ob ich mein WindowsForm-Projekt so ohne weiteres auf z. B. Linux portieren kann. Mono stellt ja z. B. ein Framework für .NET dar. Aber der Code soll deshalb nicht unnötig angepasst werden müssen. Auch wenn dieses Projekt nicht portiert werden wird will ich mir jetzt schon bestimmte Angewohnheiten für die Zukunft zulegen. Bisher hatte ich auch keine Schwierigkeiten, wenn ein Pfad in Windows letzendlich so aussieht:
Folder\Folder/Folder\Folder/File.ext
Wenn es tatsächlich Probleme geben kann, dann wäre ein Beispiel, wo es auftritt, zum Verständnis sehr hilfreich.
|
|
Ralf Jansen
      
Beiträge: 4708
Erhaltene Danke: 991
VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
|
Verfasst: Do 05.03.09 00:42
| Zitat: | Bisher hatte ich auch keine Schwierigkeiten, wenn ein Pfad in Windows letzendlich so aussieht:
Folder\Folder/Folder\Folder/File.ext
Wenn es tatsächlich Probleme geben kann, dann wäre ein Beispiel, wo es auftritt, zum Verständnis sehr hilfreich. |
Hatte eigentlich auch noch Probleme damit und vermute auch keine.
Benutze selber aber nie direkt einen Separator Character im Code sondern immer Path.PathSeparator bzw. gleich die Path.Combine Methode um Pfade zusamenzubasteln.
Man sollte so auf der sicheren Seite sein.
|
|
Christian R.
Ehemaliges Mitglied
Erhaltene Danke: 1
|
Verfasst: Do 05.03.09 01:01
Path.Combine()
Astrein. Danke.  So gefällt es auf jeden Fall auch viel besser.
|
|