in einer Generic Class new Operator verwenden?



  • Hey Leute!

    Hab mir heute mal die Generics reingezogen und komme soweit ganz gut zurecht.
    Jedoch, wie immer, stoße ich auf einen Problemfall den ich leider auch nicht googlen konnte, da mir die Begrifflichkeiten dafür fehlen um das Problem in Keywords zu fassen.

    namespace Game
    {
        class RessourceHolder<RessourceT, IdentifierT>
        {
            public List<RessourceT> mRessourceMap;        
    
            public RessourceHolder()
            {
                mRessourceMap = new List<RessourceT>();
                Load("./Media/Textures/Eagle.png");
            }
    
            private void Load(string filename)
            {
                try
                {
                    mRessourceMap.Add(new RessourceT());
                }
                catch (Exception e)
                {
                    MessageBox.Show("Datei: " + filename + " konnte nicht gefunden werden.");
                }
            }
    
            public RessourceT Get()
            {
                return mRessourceMap[0];     //get Texture within container via find for ID
            }
    
        }
    }
    

    Bitte lenkt euren Fokus auf Zeile 17.
    In meiner GenericClass RessourceHolder habe ich vor jeweils die Klassentypen in einer Map "mRessourceMap" zu fassen. Daher muss auch die jeweilige Instanz der RessourceT in die Map hinein.
    Soweit kenne ich das nur via List.Add(item).
    Problematik ist halt das ich new nicht auf RessourceT anwenden kann - ich kann mir sehr gut vorstellen das hier das Problem auch bei den Konstruktor Überladungen der jeweilig gewählten Klasse im Attribut dann später liegt. Die Methode Add() weiss ja nicht welche Überladung ich von der Klasse nutzen will.

    Ich bin sehr gespannt wie man das Ganze richtig handhabt.

    Falls ihr keine Lust habt das Ganze erneut zu erklären - gibt mir einfach ein paar Keywords damit ich selber danach suchen kann.

    MFG Charlie



  • Die Stichworte dafür lauten: Schlüsselworte (Keywords) "where" und "new" bzw. "generic constraint"
    C# where new oder C# generic constraint



  • Hey danke!

    Hauptproblem ist damit gelöst - dank where T : new().

    namespace Game
    {
        class RessourceHolder<RessourceT> 
            where RessourceT : new()
    
        {
            public List<RessourceT> mRessourceMap;        
    
            public RessourceHolder()
            {
                mRessourceMap = new List<RessourceT>();
                Load("./Media/Textures/Eagle.png");
            }
    
            private void Load(string filename)
    
            {
                try
                {
                    mRessourceMap.Add(new RessourceT());
                }
                catch (Exception e)
                {
                    MessageBox.Show("Datei: " + filename + " konnte nicht gefunden werden.");
                }
            }
    
            public RessourceT Get()
            {
                return mRessourceMap[0];    
            }
        }
    }
    

    Restproblem ist das bei einem Attribut der Klasse "Texture" es mind. einen Parameter gibt.
    Ich brauche davon lediglich eine Überladung mit einer "string" var.
    Die Tutorials zu dem Bereich sind mir jedoch noch etwas zu hoch.

    Es gibt Vorschläge mit einem
    "object initializer"
    oder
    "Activator.CreateInstance()"

    Das scheinen mir etwas weiter forgeschrittene Lösungswege zu sein.

    Ich würde aber gerne das Basisproblem erstmal richtig auffassen und wissen ob es da eine regulärere Lösung gibt. Wenn nicht dann bitte ich um Erläuterung einer der oben genannten Wege.

    Danke im Voraus schonmal für weitere Deutschüsse





  • Prof84 schrieb:

    Betreffend Deiner Intention schau Dir mal das Iterator Pattern an.

    http://de.m.wikipedia.org/wiki/Iterator_(Entwurfsmuster)

    http://www.dofactory.com/net/iterator-design-pattern

    Entschuldige aber ich kann dir mit den Verweisen nicht wirklich folgen?
    Möchtest du mir nen Ratschlag für mein "Game" Ressource Konzept geben oder soll der Verweis mir nen Deutschuss für Generic Constraints & Parameter geben?



  • Prof84 einfach ignorieren!



  • volkard schrieb:

    Prof84 einfach ignorieren!

    Ein echter volkard:
    - 0 konstruktiven Beitrag
    - 0 Bedeutung
    - 0 Selbstbewusstsein

    vom Hersteller garantiert 😃



  • Jungs... 😃

    Fechtet ihr hier einen pers. Disput in meinem Thread aus oder wie muss ich das verstehen? Zeigt eure Fachstärke und helft mir lieber 😉



  • Bei dem new-constraint kann man wirklich nur den parameterlosen Kosntruktor verwenden.
    Du könntest aber alternativ eine Schnittstelle deklarieren und diese dann für deine Resource-Klassen verwenden, z.B.

    interface IResource
    {
      public string Filename { get; set; }
    }
    

    Und diese dann als weitere Beschränkung (constraint) angeben:

    class RessourceHolder<RessourceT>
            where RessourceT : IResource, new() // new() muß immer am Ende stehen
    

    Und die Benutzung wäre dann statt über den Konstruktor:

    var resource = new RessourceT();
    resource.Filename = filename;
    mRessourceMap.Add(resource);
    

    Alternativ auch eine Methode Load(string resource) o.ä. in der Schnittstelle.

    PS: Wenn du viele verschiedene Ressourcetypen hast, dann könntest du auch eine Basisklasse (z.B. ResourceBase) benutzen, in der du dann schon die Schnittstelle definierst (anstatt immer wieder neu in der Ressource-Klasse zu erzeugen).
    PPS: Im Englischen schreibt sich Ressource nur mit einem s: Resource 😉



  • Danke für die Hilfe - klingt nach einer Lösung - werde mal ein wenig drauf rumkauen bis ich es letztendlich gerallt habe 😉

    Bei großen Fragen komme ich nochmal auf euch zurück - bis dahin...Licht aus, Hirn an 😉



  • Gut ich glaube nicht das dies eine Lösung wäre.
    Immerhin muss ich irgendwie dafür sorgen das die ResourceT Objekte in die ResourceMap gelangen also in die List. Da der Aufruf später über diese Liste erfolgen soll.

    Siehe Methode Get()
    (welche noch nicht geschrieben ist)

    Außerdem geht das leider mit dem Interface den Resource Klassen anfügen nicht. Ich nutze SFML.NET API und dort sind die Klassen halt festgelegt - möchte die Dinger ungern abändern.



  • Hier auch ein Versuch von mir zu deiner Idee:

    ResourceT resource = new ResourceT();
    resource.filename = "./path/pic.png";
    mResourceMap.Add(resource);
    

    Das Prinzip welches du meinst habe ich verstanden. Ich umgehe den Konstruktor in dem Falle hier. Leider gibt es keine public Property für filename in der Klasse. Daher keine Chance auf diesen Weg.

    Laut Galileo Buch:

    Der generische Typparameter kann nunmehr nur durch Objekte konkretisiert werden, die einen öffentlichen, parameterlosen Konstruktor unterstützen. Einen parametrisierten Konstruktor vorzuschreiben ist nicht möglich. Werden mehrere Bedingungen definiert, steht new() grundsätzlich immer am Ende der Aufzählung.

    Hier wird also nicht einmal auf ein späteres Kapitel verwiesen wo die Sache vielleicht doch gelöst worden wäre. Irgendwie schwer zu glauben das es in der großen Lösungswelt von C# keine Möglichkeit gibt. Sehnt man sich hier nach der Macht von C++ zurück?



  • Dann bleibt wohl wirklich nur

    var resource = (ResourceT)Activator.CreateInstance(typeof(ResourceT), new object[] { filename });
    

    (sieht vllt. etwas unelegant aus, entspricht aber quasi "new ResourceT(filename)")



  • Activator.CreateInstance() ist also hier die "moderne" Lösung?

    Sollte mir mal ne Doku über die Activator Klasse reinziehen - danke auf jedenfall für die Tipps Leute !



  • var resource = (ResourceT)Activator.CreateInstance(typeof(ResourceT), new object[] {filename});
                    mResourceMap.Add(resource);
    

    UND ES WERDE LICHT.

    Ich finde die Lösung garnicht mal so unelegant ehrlich gesagt. Habe einiges dazu gelernt nun - ebenfalls die Nutzung von var, an die ich mich mal langsam gewöhnen sollte.

    Vielen Danke an alle für die Hilfe !



  • Mir ist nicht ganz klar was die Klasse eigentlich machen soll.
    Also was ihr "Mehrwert" gegenüber Dictionary<string, ResourceT> ist.



  • Es ist eine Generic Klasse welche Resourcen in sich halten soll also heavyweights.

    In der Game.cs wirkt das sich dann so aus:

    ResourceHolder<Texture> mTextureHolder;
    ResourceHolder<SoundBuffer> mSoundHolder;
    [...]
    mTextureHolder = new ResourceHolder<Texture>();
    mSoundHolder = new ResourceHolder<SoundBuffer>();
    [...]
    //Load Textures
    mTextureHolder.Load("./Media/Textures/Eagle.png");
    
    //Load Sounds
    mSound = new Sound();
    mSoundHolder.Load("./Media/Sounds/wing.wav");
    
    //init mPlayer object
    mPlayer = new Sprite(mTextureHolder.Get());
    mPlayer.Position = new Vector2f(100.0f, 100.0f);
    
    //init mSound object
    mSound.SoundBuffer = mSoundHolder.Get();
    


  • OK.
    Jetzt verstehe ich es noch weniger.

    Wieso nicht einfach

    Texture mTexture;
    SoundBuffer mSound;
    [...]
    mTexture = null;
    mSoundBuffer = null;
    [...]
    //Load Textures
    mTexture = new Texture("./Media/Textures/Eagle.png");
    
    //Load Sounds
    mSoundBuffer = new Sound("./Media/Sounds/wing.wav");
    
    //init mPlayer object
    mPlayer = new Sprite(mTexture);
    mPlayer.Position = new Vector2f(100.0f, 100.0f);
    
    //init mSound object
    mSound.SoundBuffer = mSoundBuffer.Get();
    

    ?

    ps.

    heavyweights

    Eine Reosource-Holder Klasse für Schwergewichte ohne IDisposable?



  • hustbaer schrieb:

    OK.
    Jetzt verstehe ich es noch weniger.

    Wieso nicht einfach

    Texture mTexture;
    SoundBuffer mSound;
    [...]
    mTexture = null;
    mSoundBuffer = null;
    [...]
    //Load Textures
    mTexture = new Texture("./Media/Textures/Eagle.png");
     
    //Load Sounds
    mSoundBuffer = new Sound("./Media/Sounds/wing.wav");
     
    //init mPlayer object
    mPlayer = new Sprite(mTexture);
    mPlayer.Position = new Vector2f(100.0f, 100.0f);
     
    //init mSound object
    mSound.SoundBuffer = mSoundBuffer.Get();
    

    ?

    ps.

    heavyweights

    Eine Reosource-Holder Klasse für Schwergewichte ohne IDisposable?

    Naa Hustbaer du darfst mich nicht überschätzen ich bin ein Anfänger und im Bezug mit IDiposable noch keinen Kontakt - ich folge nur einem Handbuch zum Game Design mit SFML API. Und dort wird eine ResourceHolder Template Klasse als Beispiel genannt.

    Ich verstehe deinen Einwurf das eine Generic Klasse für das kurze Spektrum überflüssig ist. Vielleicht ist es nur eine Beispiel Angelegenheit vom Lernbuch.

    Die ResourceHolder Klasse hält ja eine Liste aller ResourceT Instanzen (somit bei TextureHolder eine Sammlung an Texturen bei SoundHolder eine Sammlung an SoundBuffer Objekten aka Sounds. Die kann ich dann für die lightweights Sound oder Sprite abrufen und das Ganze mit der Get() Methode (welche natürlich noch nen Auswahlparameter erhält). Ich finde das vom Design her garnicht soooo übel.

    Und dein Code oben überzeugt mich nicht Chef ! 🤡 Wenn dann richtig - ein bisschen lesen kann ich ja doch schon 💡



  • Was, weil ich in Zeile 1 mSound statt mSoundBuffer geschrieben habe?
    OMG ja wie furchtbar.

    Falke88 schrieb:

    und das Ganze mit der Get() Methode (welche natürlich noch nen Auswahlparameter erhält). Ich finde das vom Design her garnicht soooo übel.

    Du zeigst Code einer Klasse her die für nix gut ist und stellst dazu Fragen.
    Wenn dann einer nachfragt wozu du die Klasse eigentlich überhaupt hast kommt "na da kommt ja noch X als Funktionalität dazu". Als ob wir das riechen könnten.

    BTW: Ich sehe immer noch keinen Grund hier etwas anderes als Dictionary<string, ResourceT> zu verwenden.
    Und auch keinen Grund warum die ResourceHolder Klasse auch für das Erzeugen der Resourcen zuständig sein soll.
    Also wieso nicht einfach eine Add Funktion statt einer Load Funktion?
    (Und vielleicht merkst du jetzt warum ich immer wieder auf Dictionary<string, ResourceT> zurückkomme...)


Log in to reply