Gewinde Geschrieben 6. Dezember 2021 Teilen Geschrieben 6. Dezember 2021 Hallo zusammen, ich hätte mal eine Frage zum arbeiten mit eigenen Namensräumen und eigenen Klassenbibliotheken. Da ich jetzt meinen OnlineGrundkurs in c# fast fertig habe, würde ich gerne ein kleines Abschlussprojekt erstellen. Hierbei handelt es sich um eine kleine Konsolenanwendung, welche später in ein kleines Text Rollenspiel enden soll. Wenn ich mich etwas sicherer im Umgang mit Code fühle soll daraus eventuell eine etwas hübschere Variante in verbindung mit Xaml werden. Jetzt stoße ich allerdings erstmal auf ein kleines Problem, welches nicht wirklich mit dem Code ansich zu tun hat, sondern eher mit der Verwaltung von Projekten in VS2022. Ich habe mir eine kleine Klassenbibliothek erstellt, in welcher ich die einzelnen Characterklassen verarbeite. Diese möchte ich nun in meinem Hauptprogramm mit einbinden. Im Netz habe ich dazu gesehen, dass ich mir eine dll Datei erstelle und diese dann unter verweise mit einbinde. Soweit so gut, nach dem Einbinden sehe ich diese Dll auch unter den Verweisen in meinem Hauptcode. Ich kann jedoch nicht darauf zugreifen. Auf einem anderen Rechner hatte dies allerdings funktioniert, ich habe allerdings keinen blassen Schimmer woran es auf meinem StandPC scheitert, außer das auf dem anderen Rechner VS2019 läuft (ich möchte einfach bezweifeln das es daran liegt). Darauf hin habe ich mir gedacht, einfach meinen eigenen Namespace mit einzubinden. In diesem Namespace befindet sich ja meine Klassenbibliothek. Allerdings funktioniert auch dieser Versuch nicht wirklich. Selbst wenn ich die Hilfe aus dem Netz von Microsoft selber nutze und alles wie dort beschrieben durchführe, schaffe ich es nicht beide Projekte mit einander zu verbinden. Kann mir vielleicht jemand von euch helfen, wie es möglich wird meine Klassenbibliothek bzw. einen von mir erstellten Namensraum in einem anderen projekt nutzbar zu machen oder generell 2 Projekte in ein Projekt umzuwandeln? freundliche Grüße Gewinde 🙂 Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
0x00 Geschrieben 6. Dezember 2021 Teilen Geschrieben 6. Dezember 2021 Grundsätzlich ist deine Herangehensweise goldrichtig. Du musst deine Assembly (deine Klassenbibliothek) in das entsprechende Projekt laden und dann noch den entsprechenden Namespace referenzieren. Allerdings kann es sein, dass du dann deine Klassen immer noch nicht nutzen kannst. Die braucht nämlich noch den korrekten Access Modifier: public. Falls deine Klassen mit "public class" beginnen haben sie den Access Modifier "public", was in deinem Fall der richtige ist. Wenn deine Klassen jedoch nur mit "class" beginnen wird der default Access Modifier "internal" verwendet. In diesem Fall (oder wenn du sonst einen anderen Access Modifier außer public verwendest) solltest du diesen auf public ändern. Allerdings musst du den Access Modifier nur für die Klassen ändern, die du auch außerhalb deiner Assembly (deines Projektes) aufrufen willst. Wenn du die Klassen A und B in deiner Bibliothek hast, aber nur A von außerhalb aufrufen willst, muss auch nur A den public Access Modifier haben. B kann ihn zwar haben, braucht ihn aber nicht. Selbiges gilt für Methoden. Willst du eine Methode einer Klasse von außerhalb deiner Assembly aufrufen müssen sowohl die Klasse, als auch die Methode den public Access Modifier haben! vor einer Stunde schrieb Gewinde: Kann mir vielleicht jemand von euch helfen, wie es möglich wird meine Klassenbibliothek bzw. einen von mir erstellten Namensraum in einem anderen projekt nutzbar zu machen oder generell 2 Projekte in ein Projekt umzuwandeln? Wie hast du es denn im Moment gelöst? So wie ich das verstanden haben hast du zwei seperate Projekte (und auch zwei Solutions? Oder gar keine Solutions?), die du aber nur in Kombination nutzt? In diesem Fall wäre die eleganteste Lösung beide Projekte in einer Solution zu kombinieren. Dann kannst du auch einfach die Referenz zu deiner Klassenbibliothek mit Add -> Add Project Reference hinzufügen. Man kann ein Projekt auch kompilieren und dann die kompilierte .dll referenzieren, allerdings hat diese Variante einen entscheidenden Nachteil: Wenn du deine Klassenbibliothek veränderst musst du jedes Mal daran denken diese wieder zu kompilieren, damit die korrekte Version in deinem anderen Projekt verwendet wird. Wenn du jedoch beide Projekte in der selben Solution kombinierst musst du nur die Solution bauen wodurch automatisch alle Projekte kompiliert werden. Dadurch hast du stets die neuste Version deiner Klassenbibliothek in deiner Konsolenanwendung. Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
Gewinde Geschrieben 6. Dezember 2021 Autor Teilen Geschrieben 6. Dezember 2021 Danke für die schnelle Antwort. Ich habe gerade nochmal nachgesehen und habe auf dem einen Rechner tatsächlich public gewählt und auf dem anderen Rechner internal. Allerdings habe ich bei der Variante mit dem internal Zugriffsmodifizierer für alle Klassenmember public getter und setter sowie einen public Konstruktor integriert. Ist es zwingend notwendig alle dort im Namespace befindlichen Klassen Öffentlich zu gestalten? Ich hatte diese bei der zweiten Version ja bewusst internal gewählt um den Zugriff nur über die implementierten getter und setter zu ermöglichen. Auf meinem Laptop ( da wo der Zugriff auch funktioniert) habe ich mir eine CharClass.dll erstellt und mittels using den Namespace integriert, allerdings sind es weiterhin einzelne Projekte. Wie fügt man denn beide Projekte in ein Projekt zusammen, so das ich auf den gesamten Code beider Projekte zugreifen kann? Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
Whiz-zarD Geschrieben 6. Dezember 2021 Teilen Geschrieben 6. Dezember 2021 Wenn die Klasse als internal deklariert ist, kann eine Instanz dieser Klasse nur innerhalb des Projektes erzeugt werden. Ganz egal, ob du den Konstruktor oder die Eigenschaften mit public deklariert hast. Die Klasse ist nun mal außerhalb des Projektes nicht sichtbar. D.h. wenn du eine Instanz dieser Klasse in einem anderen Projekt erzeugen möchtest, dann muss die Klasse auch zwinged als public deklariert sein. Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
0x00 Geschrieben 6. Dezember 2021 Teilen Geschrieben 6. Dezember 2021 vor 45 Minuten schrieb Gewinde: Danke für die schnelle Antwort. Ich habe gerade nochmal nachgesehen und habe auf dem einen Rechner tatsächlich public gewählt und auf dem anderen Rechner internal. Allerdings habe ich bei der Variante mit dem internal Zugriffsmodifizierer für alle Klassenmember public getter und setter sowie einen public Konstruktor integriert. Ist es zwingend notwendig alle dort im Namespace befindlichen Klassen Öffentlich zu gestalten? Ich hatte diese bei der zweiten Version ja bewusst internal gewählt um den Zugriff nur über die implementierten getter und setter zu ermöglichen. Hier musst du zwischen zwei Fragen unterscheiden: "Muss ich alle Klassen im Namespace öffentlich machen?" und "Muss ich die Klasse public machen obwohl Getter und Setter der Property schon public sind?". Zur ersten Frage: Nein. Du musst nur alle Klassen public machen, auf die du von außen zugreifen willst. Willst du nur von intern zugreifen muss die Klasse nicht public sein. Zugriff von außen schließt allerdings auch Zugriffe auf Methoden und Properties mit ein. Wo wir dann bei der zweiten Frage wären: Wenn eine Klasse nicht public ist, können alle Methoden und Properties public sein, du kannst trotzdem nicht von außen zugreifen. Wenn eine Klasse public ist, heißt das im Umkehrschluss aber nicht, dass du auf alles von außen drauf kommst. Sondern nur auf die public Properties und Methoden. Es muss also sowohl die Klasse als auch deren Methode public sein, wenn du auf die Methode zugreifen willst. Selbiges gilt für Properties. Ein paar Beispiele: // Internal class, du kommst nicht von außen drauf. internal class MyInternalClass { // Internal Method. Das "internal" hier hat keinen Effekt, da bereits die Klasse internal ist. // Jeder in dieser Assembly kann sowohl auf die Klasse als auch auf die Methode zugreifen. internal void SomeInternalMethod(); // Public Methode. Das "public" hier ist ebenfalls unnötig, da das "internal" der Klasse limitierend ist. // Das "public" signalisiert zwar theoretisch, dass du von außerhalb der Assembly auf diese Methode zugreifen, aaaaaber: // Du kannst nicht auf die Klasse von außerhalb der Assembly zugreifen! // Und da die Methode nur über die Klasse aufgerufen werden kann (MyInternalClass.SomePublicMethod()), kommst du von außen nicht auf die Methode. // Trotz public access modifier! public void SomePublicMethod(); } // Public class. Du kommst von außerhalb drauf. public class MyPublicClass { // Public Method. Da sowohl die Klasse als auch die Methode public sind kommst du von außen drauf. public void SomePublicMethod(); // Die Klasse ist zwar public, aber nicht die Methode! // Du kommst zwar auf die Klasse, kannst diese Methode aber nicht von außen aufrufen! internal void SomeInternalMethod(); } Wenn du Access nach außen limitieren willst musst du folgendes beachten: 1. Die Klasse die den Access bereitstellt muss public sein. 2. Der Getter muss ebenfalls public sein. 3. Die Klasse die du exposed muss auch public sein (so blöd es klingt!). Du kannst keinen public Getter für eine internal class haben. Der Getter einer Property (oder der Return Wert einer Methode), darf nur Objekte einer Klasse zurückgeben, die mindestens die selbe Visibility hat wie der Getter bzw. die Methode. Ein Internal Getter der eine public Class zurückgibt ist okay. Ein public Getter der eine internal Class zurückgibt nicht! Sonst würdest du ja ein Objekt zurückgeben, was eigentlich in dem Scope (außerhalb der Assembly) nicht exisitieren darf. Nun kannst du aber dennoch den Access limitieren. Die Klasse auf die du den Access limitieren willst muss zwar public sein, aber deren Methoden und Properties nicht! So kannst du die Klasse nach außen nur mit den Methoden und Properties exposen, die du auch nach außen geben willst. Ein weit verbreitetes Beispiel wäre z.B. so eine Klasse: // Class muss public sein, da außerhalb der Assembly mit ihr gearbeitet werden muss! public class MyClass { // Public property mit public getter und internal setter. // MyInteger kann also von außerhalb ausgelesen, aber nur von intern gesetzt werden! public int MyInteger { get; internal set; } } So kannst du deine Daten vor Modifikation schützen oder verhindern, dass Methoden aufgerufen werden, von denen du nicht willst, dass sie aufgerufen werden. Eine solche Methode kann z.B. auch der Konstruktor sein. Wenn du den Konstruktor auf internal setzt kannst du nur innerhalb der Assembly Objekte dieser Klasse erzeugen - während du trotzdem außerhalb mit ihr arbeiten kannst. // Public class. Exposed über Property SecretClass. public class ExposerClass { // Public Property erlaubt Access auf SecretClass. // AccessClass kann von außen geholt (und theoretisch auch gesetzt) werden, allerdings ist der Ctor der SecretClass internal. // SecretClass Objekte kann man also nur innerhalb dieser Assembly instanziieren. public SecretClass { get; set; } } // Class muss public sein, da sie über eine public Property exposed wird. public class SecretClass { // Ctor ist internal, damit man diese Klasse nur innerhalb dieser Assembly instanziieren kann. internal SecretClass() } vor 45 Minuten schrieb Gewinde: Auf meinem Laptop ( da wo der Zugriff auch funktioniert) habe ich mir eine CharClass.dll erstellt und mittels using den Namespace integriert, allerdings sind es weiterhin einzelne Projekte. Wie fügt man denn beide Projekte in ein Projekt zusammen, so das ich auf den gesamten Code beider Projekte zugreifen kann? Erstell eine neue Solution. Dann kopier deine zwei Projektordner in den Ordner der Solution, die Projektordner sollte auf der selben Ebene wie die .sln Datei sein. Das ganze sollte dann in etwa so aussehen: SLNFolder MySln.sln ProjectA ProjectA.csproj (Other files from your projects - for example the .cs files) ProjectB ProjectB.csproj (Other files from your projects - for example the .cs files) Dann öffne die Solution und klicke auf "Add existing project". Da fügst du nun die .csproj Dateien der zwei Projekte hinzu. Nun sollten beide Projekte in der Solution sein. Randnotiz: Wenn du eine neue Solution erstellst wird meist ein leeres Projekt miterstellt. Das kannst du einfach löschen Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
Gewinde Geschrieben 7. Dezember 2021 Autor Teilen Geschrieben 7. Dezember 2021 Hallo zusammen, habe meine Idee zum einfacheren Verständnis mal etwas vereinfacht nachgestellt und es hat wie gesagt funktioniert. Ich habe jetzt meine Klasse im Zweiten Namensraum public gemacht und den Zugriff auf die interne Variable sex mittels einem private setter internal gelassen. Ich hoffe damit habe ich die Problematik verstanden. Das mit dem hin und her kopieren muss ich dann als nächstes mal versuchen. using System; using ZweiterNamespace; namespace ErsterNamespace { internal class Program { static void Main(string[] args) { Character character = new Character(); string input; Console.ForegroundColor = ConsoleColor.Green; Console.WriteLine("Geschlecht eingeben: "); Console.WriteLine(); Console.WriteLine("[1] Neuter"); Console.WriteLine("[2] Male"); Console.WriteLine("[3] Female"); Console.ForegroundColor = ConsoleColor.White; Console.WriteLine(); input = Console.ReadLine(); character.SetSexInput(input); Console.WriteLine(character.ToString()); Console.ReadKey(); } } } namespace ZweiterNamespace { public enum Geschlecht { Neuter, Male, Female} public class Character { internal Geschlecht sex; public Geschlecht Sex { get { return sex; } internal set { sex = value; } } public Character() { } public void SetSexInput(string input) { switch (input) { case "1": this.Sex = Geschlecht.Neuter; break; case "2": this.Sex = Geschlecht.Male; break; case "3": this.Sex = Geschlecht.Female; break; } } public override string ToString() { return "Das Geschlecht des Objekts ist " + Sex; } } } Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
Gewinde Geschrieben 7. Dezember 2021 Autor Teilen Geschrieben 7. Dezember 2021 Der Test mit dem hinzufügen der Verweise und der usingdirektive in VS2022 war ebenso erfolgreich. Komischerweise funktiniert das mit dem Kopieren bei mir nicht, aber das wird wohl eher an meiner Wenigkeit liegen. Ich versuche es noch etwas bis ich auch das raus habe. Ich danke euch allen wiedermal für eure erstklassige Hilfe. 👍 Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
Whiz-zarD Geschrieben 7. Dezember 2021 Teilen Geschrieben 7. Dezember 2021 (bearbeitet) Anstatt public Geschlecht Sex { get { return sex; } internal set { sex = value; } } kannst du auch einfach public Geschlecht Sex { get; internal set; } schreiben. Das sind dann sog. autogenerated properties. Der Compiler generiert daraus dann folgenden Code: private Geschlecht _sex; public Geschlecht get_sex() { return _sex; } internal void set_sex(Geschlecht value) { _sex = value; } Und das ist genau das, was du willst. Properties sind also sog. sytaktischer Zucker, welches die Schreiberei ein wenig abnimmt. Ein weiterer Tipp: Die Methode SetSexInput() hat nichts in der Character-Klasse zu suchen, da sie in der Abhängigkeit der Benutzereingabe steht. Angenommen, du verwendest nun eine grafische Oberfläche anstatt eine Konsole und du kannst über die grafische Oberfläche einen Radiobutton setzen. Dann wäre die Methode SetSexInput() überflüssig und würde nur ein Grundrauschen in der Character-Klasse erzeugen. Anstatt die Methode in die Character-Klasse zu implementieren, könnte man auch eine Factory- oder Builder-Klasse bauen, die dir anhand der Benutzereingaben eine Instanz der Character-Klasse erzeugt. Bearbeitet 7. Dezember 2021 von Whiz-zarD Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
Empfohlene Beiträge
Dein Kommentar
Du kannst jetzt schreiben und Dich später registrieren. Wenn Du ein Konto hast, melde Dich jetzt an, um unter Deinem Benutzernamen zu schreiben.