Moin,
mal eine ganz bescheidene Frage:
Wie umgehe ich am geschicktesten das "ableiteverbot" bei Basistypen wie String, Int, ...
Will solche funktionen wie "undo"... implementieren
Viele Grüße
Ernst
Man muß nichts wissen,
man muß nur wissen wer es wissen könnte
oder wo es steht😉
Hallo bigeddie,
Will solche funktionen wie "undo"... implementieren
Dann ist das Ableiten sicherlich ein falscher Weg.
Besser geeignet ist auf jeden Fall das Multilevel-Undo/-Redo mit dem Command-Muster
Ansonsten, um eine Funktion nachträglich zu einer Klasse/Interface hinzuzufügen, kannst du auch extensions Methods verwenden.
Eine auch sehr gut geeignete Undo/Redo-Funktion ist unter Generic Memento Pattern for Undo-Redo in C# zu finden.
Es gibt 3 Arten von Menschen, die die bis 3 zählen können und die, die es nicht können...
Nicht dass wir uns falsch verstehen,
Die Typen welche ich brauche, sollen z.B. auch Spaltennamen und Anzeigenamen enthalten um z.B. einen UPDATE-Befehl für SQL generieren zu können in dem ich neinfach nur das Objekt an einen generator übergebe...
Man muß nichts wissen,
man muß nur wissen wer es wissen könnte
oder wo es steht😉
z.B. auch Spaltennamen und Anzeigenamen enthalten
Trotzdem ist Ableitung der falsche Weg.
Wie wäre es mit einer Komposition? Zum Beispiel:
public class Entry<T>
{
public T Value { get; set; }
public string ColumnName { get; set; }
//...
}
Allerdings bleibt die Frage, warum diese Informationen direkt in Verbindung mit dem Wert gespeichert werden müssen.
Wenn ich eine Klasse habe, welche ihre Daten in eine Datenbank speichert und ich z.B. einen Updatestring(SQL) erstellen möchte ist es doch effizienter wenn ich nur die Daten updaten lasse, welche auch wirklich geändert wurden, oder?
Datatable arbeitet soweit ich verstanden habe nach einem ähnlichen Prinzip, sprich erstellt auch nur für die Daten die geändert wurden einen updatebefehl.
Man muß nichts wissen,
man muß nur wissen wer es wissen könnte
oder wo es steht😉
Werttypen (auch Strings) im DOT NET können nicht feststellen, dass sie geändert wurden, da sie als Immutable implementiert worden sind (was an sich auch richtig ist).
Deshalb brauchst du eine Klasse, die Änderungen erkennt und diese auch festhält sowie den aktuellen Zustand an dein DataSet oder sonst wo ausliefert.
Hast du dir die geposteten Links mal angesehen? Alle beide enthalten entsprechende (unterschiedliche) Lösungen für dein Problem.
Es gibt 3 Arten von Menschen, die die bis 3 zählen können und die, die es nicht können...
Werttypen (auch Strings) im DOT NET können nicht feststellen, dass sie geändert wurden, da sie als Immutable implementiert worden sind (was an sich auch richtig ist).
Das ist meines Erachtens so pauschal nicht korrekt.
string ist immutable, und Delegates zB auch. Aber ein int oder ein float ist doch nicht immutable?
Wissensvermittler und Technologieberater
für .NET, Codequalität und agile Methoden
@bigeddie:
Du willstr also den 187. ORMapper selber schreiben?
Der Ansatz von winSharp93 scheint mir für die Aufgabe eigentlich am plausiebelsten.
Vielleicht erfinde ich ja auch das Rad nochmal neu, aber mir geht es darum zu sehen ob es funktionieren kann (nennt man glaube ich Grundlagenforschung auf unterstem Level).
Meine Intension ist es z.B. auch für Abfragen mit mehreren JOINS die Daten ändern zu können (z.B. beim Update die Änderungen wieder in die entsprechende Tabelle zurückschreiben zu können) ohne mir selbst ein Loch ins Knie zu schießen.
(Klar kann ich nur wenn die Namen der Spalten eindeutug sind....)
Man muß nichts wissen,
man muß nur wissen wer es wissen könnte
oder wo es steht😉
Du kannst das höchsten über Proxies machen, wie dem CastelProxy oder dem Proxy von LinFu.
Aber das ist eher das Pferd von der "falschen" Seite aufzäumen.
Jojns werden auch in ORMappern meist mit verarbeitet, nur das sie dort
dann meist als eigenständige Objekte in dem DTO/BO auftauchen.
Deshalb bieten die meisten ORMapper ein LazyLoading ( lädt die Unterobjekte nach wenn sie benötigt werden )
oder ein EagerLoading ( alles wird gleich zusammen gelesen ) an.
Dadurch ist das schreiben wiederum einfach.
"Selbst" das EntityFramework bietet soetwas an.
Aber wenn Du es nur zu forschungszwecken machen willst, versuch mal die sache mit dem Proxy.
Bei Codeproject gibt es zu LinFu etwas dazu.
string ist immutable, und Delegates zB auch. Aber ein int oder ein float ist doch nicht immutable?
Doch ich denke schon das Int, Float usw. immutable ist. Immutable bedeutet ja, das das Objekt (egal ob Klasse oder Struktur) keine Funktionen hat, die einen Wert von sich selbst ändern, sondern ein neues Objekt zurückgeben, mit neuem Wert.
Es gibt 3 Arten von Menschen, die die bis 3 zählen können und die, die es nicht können...
Hallo Golo Roden,
Objekte macht man immutable, damit man sie in ein anderes Objekt übernehmen kann (Setter) bzw. sie aus einem anderen Objekt herausgeben kann (Getter), ohne es kopieren zu müssen und trotzdem die Kapselung des anderen Objekts nicht verletzt.
Wäre String nicht immutable, würde der folgende Code unter Verletzung der Kapselung den Zustand des Personen-Objektes ändern.
Person p = new Person ("Peter, Pan");
String name = p.Name;
name.Substring (0, 5); // Angenommen, String wäre nicht immutable
Console.WriteLine (p.Name); // Gäbe "Peter" aus
Nun ist diese Problematik bei Werttypen sowieso nicht in dem Maße gegeben, weil bei Werttypen durch eine Zuweisung immer der Inhalt kopiert wird.
Person p = new Person (new DateTime (1892, 5, 1));
DateTime dateOfBirth = p.DateOfBirth;
dateOfBirth.Year = 2000; // Angenommen, DateTime wäre nicht immutable
Console.WriteLine (p.DateOfBirth); // Gäbe trotzdem immer noch 01.05.1892 aus
Trotzdem würde ich es so sehen, wie kleines_eichhoernchen. Immutable ist ein Objekt dann, wenn es keine Properties und Methoden anbietet, die seinen Zustand ändern.
herbivore
Okay, auch die MSDN sagt zu Int32
"Members that appear to modify instance state actually return a new instance initialized with the new value."
Das heißt für mich dann quasi "immutable".
Wissensvermittler und Technologieberater
für .NET, Codequalität und agile Methoden
In object-oriented and functional programming, an immutable object is an object whose state cannot be modified after it is created
Int32 (Framework Class Library)
MSDN: Int32 Structure
Thread Safety
All members of this type are thread safe. Members that appear to modify instance state actually return a new instance initialized with the new value. As with any other type, reading and writing to a shared variable that contains an instance of this type must be protected by a lock to guarantee thread safety.
Ist also immutable!
int i = 4;
int a = i;
i = 6;
Console.WriteLine(a); // >> 4
Console.ReadLine();
Gruß Timo
Hallo zusammen,
Members that appear to modify instance state actually return a new instance initialized with the new value.
hm, ich will mir ja nicht selbst widersprechen und tue das auch nicht, denn ich hatte ja immutable etwas weniger strikt definiert. Trotzdem halte ich diese Aussage aus der MSDN für falsch. Immerhin gibt es Operatoren wie ++, += u.ä. Und die ändern bei int & Co doch den Wert. Aber in Bezug auf Enthaltensein und Properties, wie ich das oben beschrieben habe, ändert das nichts an dem von mir Gesagten.
herbivore
Wäre nach deiner Aussage nicht auch String mutable?
String v = "asd";
v += "a";
Console.WriteLine(v); // >> asda
Gruß Timo
Werttypen:
MSDN: Werttypen (C#-Referenz)
Unterteilen sich wie folgt:1.Strukturen
a Numerische Typen
b Ganzzahlige Typen
c Gleitkommatypen
d decimal
e bool
f Benutzerdefinierte Strukturen
1.Enumerationen
Alle Werttypen werden implizit von System.ValueType abgeleitet.
Vererbungshierarchie System.Object -System.ValueType
Na komisch ich dachte immer Strukturen wären keine Objekte! *g ValueType überschreibt nur viel von Object. Keine Ahnung was das jetzt genau bedeutet bin verwirrt! *g
Gruß Timo
Hallo Omit,
Wäre nach deiner Aussage nicht auch String mutable?
nein, durch += wird das Originale-String-Objekt nicht geändert, sondern es wird ein neues Objekt erzeugt. Die Referenz auf das neue Objekt landet in der Variablen v.
Na komisch ich dachte immer Strukturen wären keine Objekte!
Das kommt darauf an, was genau man unter dem Begriff Objekt versteht. Der wichtige Unterschied ist, dass bei einem Werttyp in einer Variablen der Wert/das Objekt und bei einem Referenztyp in einer Variablen eine Referenz auf den Wert/das Objekt gespeichert wird.
herbivore
Ich kenne schon den Unterschied von Referenz-Typen und Wertetypen. Doch hat mich das es etwas irritiert, dass auch ValueTypes von Object erbt, da ich das so nicht erwartet hätte. Folgende Erklärung ergibt in dem Hinblick nur noch bedingt Sinn.
Value Types:
In C#, all the "things" declared with the following list of type declarations are Value types (because they are from System.ValueType):
bool
...
ushortReference Types:
All the "things" declared with the types in this list are :::
class
interface
delegate
object
string
Ach jetzt verstehe ich, was du meinst.(Glaube ich zumindest 😉)
Da Int32 direkt auf den Heap verweist und nicht wie String erst auf den Stack.
Es wird mit += oder so, kein neuer Bereich auf dem Heap allokiert, sondern der bestehende Eintrag auf dem Heap geändert.
Wo hingegen bei String eine neue String-Referenz im Stack angelegt wird, die auf einen neu allokierten Bereich im Heap verweist.
So langsam frag ich mich ob es überhaupt sinnvoll ist sich darüber zu Unterhalten ob ein Valuetype immutable ist.
Aber im Prinzip verhält sich Int32 wie ein Immutable Object.
Das ganze wird jetzt etwas philosophisch und hängt "nur"(*g) von der Art ab wie man immutable defeniert.
Aber wie sieht es mit boxed Int aus:
int? a = 0;
Sieht für mich auch immutable aus.
Gott so Details können ganz schon verwirrend sein, geht das nur mir so?
Gruß Timo
Hallo Omit,
Es wird mit += oder so, kein neuer Bereich auf dem Heap allokiert, sondern der bestehende Eintrag auf dem Heap geändert.
im Prinzip ja, auch wenn du in deinem Beitrag überall Heap und Stack vertauschen müsstest, damit es halbwegs hinhaut. 🙂
So langsam frag ich mich ob es überhaupt sinnvoll ist sich darüber zu Unterhalten ob ein Valuetype immutable ist.
Das hängt eben von der Definition ab. Natürlich kann man eine Werttyp-Variable durch Zuweisung ändern. Aber ich hatte immutable ja extra so definiert, dass es keine Properties und Methoden gibt, die das Objekt ändern. Ich habe jetzt mal genauer geguckt. Dass a += b
in a = a + b
umgesetzt wird, hatte ich sowieso vermutet. +=
ist somit eigentlich kein Sonderfall, sondern letztendlich nur eine Änderung durch Zuweisung. Bei ++i
hatte ich allerdings nicht vermutet, dass das in i = i + 1
umgesetzt wird, sondern hatte eher eine extra Increment-Operation erwartet. Allerding erzeugt ++i
tatsächlich genau den gleichen IL-Code wie i = i + 1
. Somit auch hier kein Sonderfall, sondern wieder nur eine Änderung durch Zuweisung. Insofern ziehe ich
Trotzdem halte ich diese Aussage aus der MSDN für falsch. Immerhin gibt es Operatoren wie ++, += u.ä. Und die ändern bei int & Co doch den Wert.
zurück und bleibt es also doch bei
Members that appear to modify instance state actually return a new instance initialized with the new value.
Abgesehen natürlich von der Zuweisung, aber das ist ja sowieso klar und für alle Werttypen gleich.
Aber wie sieht es mit boxed Int aus:
int? a = 0;
Sieht für mich auch immutable aus.
Jipp!
herbivore
Aber wie sieht es mit boxed Int aus:
int? a = 0;
Sieht für mich auch immutable aus.
Hm, also meiner Auffassung nach ist boxed int schon mal was ganz anderes als int?. Boxed int wäre eher sowas:
Object a = 0;
also die Zuweisung einer ValueType-Konstante (0) zu einer Variable eines Typs, der nicht von ValueType erbt, wodurch für diese Konstante Speicher auf dem Heap reserviert werden muss, während
int? a = 0;
eine Zuweisung der 0 zu einer Nullable<int> Struktur ist, die ganz ähnlich zu int von ValueType abgeleitet ist und der Begriff immutable damit Definitionssache ist. Nach untenstehender Definition wäre int? immutable, ja.
Aber erstmal zu mutable und immutable: Man kann immutable ja auch definieren als alles, was mit dem hübschen Attribut ImmutableObjectAttribute markiert ist - mit der Folge, dass man alles, was in der mscorlib steht schon mal vorweg ausklammert.
Meine Definition für mutable wäre die folgende: Eine Klasse heißt mutable, wenn sie als nicht vererbbar gekennzeichnet ist, nicht abstrakt ist und mindestens eine nicht statische, öffentliche Methode existiert, für die Parameter existieren, sodass diese Methode mindestens ein Feld (und damit den inneren Zustand des Objekts) derselben Instanz verändert. Nach IL-Sinn sind allerdings auch Property-Setter als Methoden zulässig.
Leider kann man die Implementierung von String im Reflector nicht sehen, aber anhand der Tatsache, dass keine öffentliche Methode von String dieselbe String-Instanz verändert sondern wenn schon denn schon eine neue String-Instanz zurückgibt, kann man schon sagen, dass String immutable ist. Bei Int16, Int32, Int64 und wie sie alle heißen sieht die Sache nicht anders aus, auch die sind immutable.
Interessanterweise sind aber nicht alle von ValueType erbenden Objekte immutable. Alle Enums sind immutable und alle in der mscorlib definierten Zahlendatentypen auch - aber System.Drawing.Size aus der System.Drawing ist beispielsweise mutable, allerdings sehe ich nicht wirklich einen Grund dafür, aber auch keinen dagegen (außer vielleicht, dass es erstmal verwirend ist).
Ach ja und
Es wird mit += oder so, kein neuer Bereich auf dem Heap allokiert
Doch, mit += wird neuer Speicher allokiert, da wie herbivore in seinem Beitrag auch geschrieben hat a += b zu a = a + b umgesetzt wird.
Hi herbivore,
im Prinzip ja, auch wenn du in deinem Beitrag überall Heap und Stack vertauschen müsstest, damit es halbwegs hinhaut. 🙂
ich war mir schon unsicher, hätte es dann doch eher nochmal nachschauen sollen! 😉
Gruß Timo
System.Drawing.Size aus der System.Drawing ist beispielsweise mutable, allerdings sehe ich nicht wirklich einen Grund dafür
Wenn du eine immutable-Size Struktur haben möchtest, musst du entweder sie als quasi readonly implementieren und mit Operatoren überladen oder aber du musst eine readonly property haben und eine extra Funktion (kein Set-Property) um den neuen Wert zu setzen. Beispiel:
struct Size {
private int x;
public int X { get { return x; } }
public Size SetX(int value) { return new Size(value, y); }
private int y;
public int Y { get { return y; } }
public Size SetY(int value) { return new Size(x, value); }
public Size(int x, int y) { this.x = x; this.y = y; }
}
Es gibt 3 Arten von Menschen, die die bis 3 zählen können und die, die es nicht können...
Angenommen, ich will einem Objekt, was eine Size-Property bereitstellt eine neue Höhe verpassen, dann ist ja klar, dass sowas
obj.Size.Height = newHeight;
nicht zum Ziel führt (teilweise merkt der Compiler das sogar und meckert rum). Also muss man die Struktur erstmal in einer Variablen zwischenspeichern:
Size s = obj.Size;
s.Height = newHeight;
obj.Size = s;
Das setzt aber voraus, dass Size mutable ist. Aber es geht ja bei einer so simplen Struktur auch deutlich einfacher, ohne zusätzliche Variable und ohne unnötige Voraussetzungen, ob Size jetzt mutable oder nicht ist:
obj.Size = new Size(obj.Size.Width, newHeight);
Ich frage mich lediglich, warum man dann nicht gleich alle Strukturen, die nur zwei Eigenschaften haben, als immutable implementiert hat. Weil das eigentliche Problem ist, dass man, wenn die Struktur mutable ist, auch über die Variante ganz oben nachdenken könnte, und die folgt zwangsläufig zu einem Bug.
//edit: schließenden CSHARP-Tag vergessen
Hi it´s me again😉
Also um nochmal auf das eigentliche Thema zurückzukommen...
Ich müsste also quasi für jeden Basistyp einen eigenen Type oder nach dem Code den winSharp93 gepostet hat, erstellen in welchem ich dann die Anforderungen, welche ich an den Type habe (z.B. ein Pattern welches mir die Validität des im entsprechenden String-Typs z.B.CSString abzulegenden Wertes z.B. in einer Seter-Methode prüft und mir ggf. eine Exception generiert wenn der übergebene String nicht valide ist?
Undo wäre dadurch auch problemlos möglich....
Viele Grüße
Bigeddie
Man muß nichts wissen,
man muß nur wissen wer es wissen könnte
oder wo es steht😉
Hallo bigeddie,
an sich wurden schon (mind.) 2 Links hier im Thread gepostet, die dein Problem lösen und auch klären, warum und wieso. Hast du dir die Links schonmal angeschaut?
Es gibt 3 Arten von Menschen, die die bis 3 zählen können und die, die es nicht können...