Zum Inhalt springen

Eigene Namensräume verwenden? Verschiedene Projekte zusammenführen?


Empfohlene Beiträge

Geschrieben

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 🙂

Geschrieben

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.

 

Geschrieben

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?

Geschrieben

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.

 

Geschrieben
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 :)

Geschrieben

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;
        }
    }
}

 

Geschrieben

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. 👍

Geschrieben (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 von Whiz-zarD

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.

Gast
Auf dieses Thema antworten...

×   Du hast formatierten Text eingefügt.   Formatierung wiederherstellen

  Nur 75 Emojis sind erlaubt.

×   Dein Link wurde automatisch eingebettet.   Einbetten rückgängig machen und als Link darstellen

×   Dein vorheriger Inhalt wurde wiederhergestellt.   Editor leeren

×   Du kannst Bilder nicht direkt einfügen. Lade Bilder hoch oder lade sie von einer URL.

Fachinformatiker.de, 2024 by SE Internet Services

fidelogo_small.png

Schicke uns eine Nachricht!

Fachinformatiker.de ist die größte IT-Community
rund um Ausbildung, Job, Weiterbildung für IT-Fachkräfte.

Fachinformatiker.de App

Download on the App Store
Get it on Google Play

Kontakt

Hier werben?
Oder sende eine E-Mail an

Social media u. feeds

Jobboard für Fachinformatiker und IT-Fachkräfte

×
×
  • Neu erstellen...