Problem beim Löschen/Hinzufügen von Objekten in einer Liste



  • solick schrieb:

    die Löschroutine sieht so aus:

    for each(dbBeobachter ^b in beobList)
    				{
    					if(b->Beobachter::get() == delName) 
    					{
    						beobList->Remove(b);
    					}
    				}
    

    sollte ich also besser:

    beobList->RemoveAll(b);
    

    verwenden?

    Du kannst nicht in einem for-each Elemente löschen oder hinzufügen; RemoveAll mit if (b->Beobachter::get() == delName) als einem Predicate<dbBeobachter ^> ^ ist vermutlich genau, was du suchst.



  • hmm ich hab versucht das Predicate nachzulesen, bin aber nicht ganz schlau daraus geworden. Was macht das genau?

    Aber mal grundsätzlich: Man kann doch aus einer Liste elemente löschen und hinzufügen. Wie verhält sich da der Enumerator?



  • solick schrieb:

    Aber mal grundsätzlich: Man kann doch aus einer Liste elemente löschen und hinzufügen. Wie verhält sich da der Enumerator?

    Wie gesagt, der Enumerator wird ungültig. Das Verhalten kennt man doch auch von den Iteratoren schon...

    solick schrieb:

    hmm ich hab versucht das Predicate nachzulesen, bin aber nicht ganz schlau daraus geworden. Was macht das genau?

    Ein Predicate<T> ist das Äquivalent zu einem Funktionszeiger bool (*)(T) ; ein solches Predicate kannst du mit RemoveAll zu benutzen, um alle Elemente durchzugehen, und diejenigen, für welche das Predicate true zurückgibt, entfernen.

    generic<typename T>
    bool p(T v)
    {
        // ...
        return false;
    }
    .
    .
    .
    Predicate<dbBeobachter ^> ^f = gcnew Predicate<dbBeobachter ^>(&p);
    // ...
    beobList->RemoveAll(f); // Alle Elemente i mit f(i)==true entfernen...
    

    MfG



  • ok vielen Dank erstmal für die Erläuterungen, werds mal versuchen umzusetzen.

    Es bedeutet aber, dass ich trotz Einsatz von Predicate nach einem löschen oder hinzufügen keine for each -Schleifen mehr auf die Liste anwenden kann, richtig?

    Also sollte ich wohl in meinem Code generell besser via Predicate auf Listen-Elemente zugreifen, oder?



  • solick schrieb:

    Es bedeutet aber, dass ich trotz Einsatz von Predicate nach einem löschen oder hinzufügen keine for each -Schleifen mehr auf die Liste anwenden kann, richtig?

    Nein. Es bedeutet nur, dass Du *während* Du in einer foreach-Schleife bist, Du die Liste nicht ändern darfst!



  • Ah ok, jetzt hab ichs verstanden. Ist ja auch logisch, er kann ja dann die Liste nicht mehr durchlaufen... manchmal sieht man den Wald vor lauter Bäumen nicht mehr...

    Danke nochmal !!

    Lg Solick



  • Hallo,

    ich hab da doch noch mal ne Frage 😉

    Die meisten Erläuerungen zu Predicates gehen dahin, dass man in der Klasse den ()-Operator überläd... Dein Code implementiert das aber nur als normale Funktion oder?

    Was ist denn jetzt besser / einfacher?

    Gruß Solick



  • solick schrieb:

    Hallo,

    ich hab da doch noch mal ne Frage 😉

    Die meisten Erläuerungen zu Predicates gehen dahin, dass man in der Klasse den ()-Operator überläd... Dein Code implementiert das aber nur als normale Funktion oder?

    Was ist denn jetzt besser / einfacher?

    Gruß Solick

    Nun, dass ist die .NET-Welt, in der du dich hier bewegst. Ein Predicate, welches du mit der Funktion RemoveAll verwenden kannst, musst du mit einem Delegate der Form

    generic<typename T>
    public delegate bool Predicate(T);
    

    ansprechen können. Ob es sich dabei intern um einen überladenen operator() handelt, oder eine Memberfunktion oder was auch immer, spielt keine Rolle. Möglich sind freilich beide Varianten. Am einfachsten wird es wohl sein, eine normale Funktion zu benutzen^^

    MfG



  • Also ich komm einfach nicht weiter:

    Predicate<acfunc::dbBeobachter ^> ^f = gcnew Predicate<acfunc::dbBeobachter ^>(&p);
    
    				for each(dbBeobachter ^b in beobList)
    				{
    					//if(b->Beobachter::get() == delName) 
    					//{
    						beobList->RemoveAll(f);
    					//}
    				}
    

    Und dann versuche ich die Funktion zu implementieren aber bekomme da nicht den Durchblick:

    generic <typename T> bool p(T v, T s)
    				{
    					if(v == s)
    					{
    						return true;
    					}
    					else
    					{
    						return false;
    					}
    
    				}
    

    Ich hab die Funktion jetzt ausserhalb der verwendenden Methode aber innerhalb der Klasse implementiert, da ich sie noch für andere Methoden bräuchte (wenns denn mal gehen würde)

    Leider ist mir in keiner Weise klar, wie ich den Vergleich implementieren soll.

    Hab diverses ausprobiert, aber ich versteh dieses Konstrukt einfach nicht. Alle beispiele sind irgendwie anders die ich finde...

    Könnt Ihr mir bitte noch einen Hinweis geben, ich steh gerade total auf dem Schlauch...

    Wieso kann ich nicht einfach eine Funktion schreiben, der ich zwei Strings übergebe und dann bei Gleichheit true, sonst false zurückgebe... Wieso muss es mit dieser Predicate Geschichte gehen?

    Lg Solick



  • solick schrieb:

    Also ich komm einfach nicht weiter:

    Predicate<acfunc::dbBeobachter ^> ^f = gcnew Predicate<acfunc::dbBeobachter ^>(&p);
    
    				for each(dbBeobachter ^b in beobList)
    				{
    					//if(b->Beobachter::get() == delName) 
    					//{
    						beobList->RemoveAll(f);
    					//}
    				}
    

    Das for each brauchst du nicht mehr, es steckt ja bereits in RemoveAll verborgen drin... das Predicate delegate wurde als generic implementiert, um die generische Verwendung zu ermöglichen. In deinem Fall brauchst du einfach eine normale Funktion vom Typ bool(dbBeobachter ^) :

    bool p(dbBeobachter ^v)
    {
        // return ... vergleich^^
    }
    

    Was die Funktion betrifft, so musst du sie selbst natürlich nicht als generic implementieren (du kannst, aber dann wird es unnötig kompliziert und sinnlos^^). Wenn du nun mit einem bestimmmten Variablen Wert vergleichen willst, so musst du dieses Predicate als Memberfunktion realisieren, und der Instanz der Klasse den Vergleichswert übergeben. Und dann ein Instanz-Member Delegate bauen...

    Wieso kann ich nicht einfach eine Funktion schreiben, der ich zwei Strings übergebe und dann bei Gleichheit true, sonst false zurückgebe... Wieso muss es mit dieser Predicate Geschichte gehen?

    Das kommt daher zustande, dass die anderen .NET Sprachen (insbesondere C#, mit welchem die Bibliotheken hauptsächlich geschrieben wurden) mehrheitlich keine Functionpointer kennen. Die Delegates sind das .NET Gegenstück dazu.

    MfG 🙂



  • So, soweit bin ich bisher gekommen:

    Aufruf innerhalb der Methode delName():

    beobList->RemoveAll(gcnew Predicate<acfunc::dbBeobachter ^>(&acfunc::BeobachterList::p,delName));
    

    Predicate-Methode p:

    bool BeobachterList::p(acfunc::dbBeobachter ^v,String ^s)
    	{
    		if(beobList->Find(s))
    		{
    			return true;
    		}
    		else
    		{
    			return false;
    		}
    
    	}
    

    Wie ihr seht, versuche ich, den String zu übergeben, der mit einer Eigenschaft des Objektes gematcht werden soll. Das scheint aber irgendwie nicht zu gehen. im unmanaged C++ kann man das wohl mit bind2nd machen, aber im managed C++ weiss ich es nicht.

    Alternativ könnte ich eine neue Variable in der Klasse einführen, der ich dann den zu matchenden String zu weise, aber das wäre ja nicht wirklich sauber.

    Leider habe ich bisher nur Anleitungen für Predicate - Verwendungen im unmanaged c++ gefunden. Dort würde ich den Operator() überladen und dann den zu matchenden String mit übergeben.

    unter -NET soll man aber explizit ein Predicate-Objekt erzeugen. Wie ich dort den String mit übergeben bekomme habe ich bisher nicht rausgefunden. Gibt es bind2nd() auch für .NET?

    Grüße solick



  • Ev. hilft Dir ein Bsp.:

    using namespace System;
    using namespace System::Collections::Generic;
    
    public ref class Person
    {
    public:
    	Person(String^ name) : _name(name)
    	{
    	}
    
    public:
    	property String^ Name
    	{
    		String^ get()
    		{
    			return _name;
    		}
    	}
    
    private:
    	String^ _name;
    };
    
    public ref class PersonFind
    {
    public:
    	PersonFind(String^ name) : _name(name)
    	{
    	}
    
    public:
    	bool Match(Person^ person)
    	{
    		if (nullptr == person || nullptr == _name)
    		{
    			return false;
    		}
    		else
    		{
    			return person->Name == _name;
    		}
    	}
    
    private:
    	String^ _name;
    };
    
    int main(array<System::String ^> ^args)
    {
    	List<Person^>^ list = gcnew List<Person^>();
    	list->Add(gcnew Person(L"Jack"));
    	list->Add(gcnew Person(L"John"));
    	list->Add(gcnew Person(L"Marc"));
    	list->Add(gcnew Person(L"Jack"));
    	list->Add(gcnew Person(L"Jack"));
    	list->Add(gcnew Person(L"Jack"));
    
    	Predicate<Person^>^ predicate = gcnew Predicate<Person^>(gcnew PersonFind(L"Jack"), &PersonFind::Match);
    	list->RemoveAll(predicate);
    
        return 0;
    }
    

    Simon



  • Danke für das Beispiel. Ich wollte dafür eigentlich keine neue Klasse implementieren, aber damit es überhaupt mal funktioniert ebend so.

    Leider gibt mir der Compiler eine recht seltsame Fehlermeldung. Habs wie folgt implementiert:

    Befehl innerhalb der Methode delName:

    Predicate<dbBeobachter ^> ^f = gcnew Predicate<dbBeobachter ^>(gcnew BeobacherFind(delName),&BeobachterFind::Match);
    
    				beobList->RemoveAll(f);
    

    Methode der Klasse BeobacherFind:

    bool BeobachterFind::Match(acfunc::dbBeobachter ^b)
    	{
    		if(b->Beobachter::get() == _name)
    		{
    			return true;
    		}
    		else
    		{
    			return false;
    		}
    
    	}
    

    Der Kompiler meckert bei der Instantierung der BeobachterFind mit delName als übergeber. Da stört er sich an der dereferenzierung auf die Methode Match.

    1>.\BeobachterList.cpp(207) : error C2061: Syntaxfehler: Bezeichner 'BeobacherFind'
    1>.\BeobachterList.cpp(207) : error C3350: "System::Predicate<T>": Ein Delegatkonstruktor erwartet 2 Argument(e).
    1> with
    1> [
    1> T=acfunc::dbBeobachter ^
    1> ]
    1>.\BeobachterList.cpp(207) : error C3699: "&": Diese Referenzierung kann nicht für den Typ "System::Predicate<T>" verwendet werden.
    1> with
    1> [
    1> T=acfunc::dbBeobachter ^
    1> ]
    1> Der Compiler ersetzt "&" durch ^", um die Analyse fortzusetzen.
    1>.\BeobachterList.cpp(207) : error C2761: 'bool acfunc::BeobachterFind::Match(acfunc::dbBeobachter ^)': Die erneute Deklaration der Memberfunktion ist unzulässig
    1>.\BeobachterList.cpp(207) : error C2143: Syntaxfehler: Es fehlt ';' vor ')'
    1>.\BeobachterList.cpp(207) : error C2143: Syntaxfehler: Es fehlt ';' vor ')'

    LG Solick



  • Ist BeobachterFind im BeobachterList.cpp bekannt?
    Inkludes gemacht?

    Simon



  • Jap.

    #Include "BeobachterFind.h"

    Daher wunder ich mich ja so... trat übrigens auch schon auf, als ich die Klasse noch in BeobachterList integriert hatte... Hab sie dann ausgegliedert hat aber nix geholfen...



  • So habs hinbekommen... war natürlich ein kleiner Schreibfehler, der mir entgangen ist.

    Vielen Dank nochmal Für eure Hilfe!!

    LG Solick


Anmelden zum Antworten