Neuer Standard C#3(oder auch VB.Net, jedenfalls kommendes Framework).
Stichwort: LinQ
Scheint irgendwie praktisch zu sein und irgendwie wollte man ähnliches auch schon immer haben.
Es ist aber eine Vermischung von strukturierter(für Althasen: prozeduraler und objektorienterter) Programmierung und funktionaler Programmierung.
Abgesehen von den Möglichkeiten, wie seht ihr die Aufweichung? Ist die Funktionale Programmierung genug isoliert? Oder ist das aktuelle Konzept noch zu Unausgereift(Gefahren in Projekten etc.). Oder sollten derartige Teile besser in andere Sprachen(innerhalb des Frameworks) ausgelagert werden? Stichwort könnte f# sein.
Oder wird es Zeit für die universale Sprache?
Ich bin gespannt auf eure Meinung.
na ja nach allem was ich über 3.0Schon gelesen habe macht es schon lust aufs ausprobieren und ich denke das die neuen Sprachkonstruckte eine echte Bereicherrung dastellen können.
Wir Arbeiten eigendlich nicht wir nehmen nur das geld
Ich finde die Erweiterungen in C# 3.0 sehr durchdacht, auch wenn die neuen Sprachfeatures eigentlich nur im Zusammenhang mit Linq Sinn ergeben ... gerade die Extension Methods sind sehr gefährlich, wenn man sie nicht sehr wohlüberlegt einsetzt.
Was die Mischung von strukturierter und funktionaler Programmierung angeht - auch heute hast Du in C# doch schon die Mischung von strukturierter und deklarativer Programmierung, Stichwort Attribute ... who cares?
Wichtig ist hierbei IMHO nur, dass die Sprache sauber ist.
C# hat meiner Meinung nach ganz andere Schwächen ...
Wissensvermittler und Technologieberater
für .NET, Codequalität und agile Methoden
Hallo ikaros,
ich habe mich mit LinQ noch nicht so intensiv beschäftigt, sondern mir nur das Anders-Hejlsber-Video LINQ on Channel9 angeschaut.
Dabei scheinen mir die Iteratoren der Kern von LinQ zu sein und die Lamda-Mimik für die Prädikate u.ä. nur eine Unterstützung. Jedenfalls finde ich nicht, dass damit die funktionale Programmierung in C# Einzug hällt. Denn auch in C# gibt es Delegaten und man kann Delegaten als Rückgabewerte liefern. Damit ist auch jetzt schon funktionale Programmierung entsprechend des Lamda-Kalküls möglich, ohne dass die Gefahr eine Unterwanderung der Sprache besteht. Die neue Syntax macht es ledigleich leichter solche Funktionen zu schreiben.
Etwas verkürzt ist LinQ eine Sammlung von hilfreichen Iteratoren beschrieben wie ich sie in Hilfreiche Iteratoren / Improving Foreach habe.
Wenn man den dortigen Source-Code um folgendes erweitert:
// In der Klasse IsoIter:
public static IIterator OrderBy (IEnumerable enumerable)
{
return new IsoIterSort (enumerable); // sic!
}
// In der Klasse Iter:
public static IIterator Where (IEnumerable enumerable,
Predicate predWhereCondition)
{
return new IterFilter (enumerable, predWhereCondition); // sic!
}
public static IIterator Select (IEnumerable enumerable,
Transformation transf)
{
return new IterTransform (enumerable, transf); // sic!
}
// als neuen Delegaten:
public delegate Object Transformation (Object obj);
// als neue Klasse:
internal class IterTransform : IIterator
{
//-----------------------------------------------------------------------
protected IEnumerator _enumerator;
protected Transformation _transf;
protected int _iCurrIndex; // Nur für CurrentIndex-Property
protected bool _fAtEnd;
//=======================================================================
public IterTransform (IEnumerable enumerable, Transformation transf)
{
_enumerator = enumerable.GetEnumerator ();
_transf = transf;
}
//=======================================================================
public void Reset ()
{
_iCurrIndex = -1;
_fAtEnd = false;
_enumerator.Reset ();
}
//=======================================================================
public bool MoveNext ()
{
if (_enumerator.MoveNext ()) {
++_iCurrIndex;
return true;
}
if (!_fAtEnd) {
++_iCurrIndex;
_fAtEnd = true;
}
return false;
}
//=======================================================================
public Object Current
{
get { return _transf == null ? _enumerator.Current
: _transf (_enumerator.Current); }
}
//=======================================================================
public int CurrentIndex
{
get { return _iCurrIndex; }
}
//=======================================================================
public IEnumerator GetEnumerator ()
{
return this;
}
}
dann kann man das folgende LinQ-Beispiel
string[] names = { "Burke", "Connor", "Frank",
"Everett", "Albert", "George",
"Harris", "David" };
IEnumerable<string> expr = from s in names
where s.Length == 5
orderby s
select s.ToUpper();
foreach (string item in expr)
Console.WriteLine(item);
}
schreiben als
string[] names = { "Burke", "Connor", "Frank",
"Everett", "Albert", "George",
"Harris", "David" };
IEnumerable expr =
IsoIter.OrderBy (
Iter.Select (
Iter.Where (
names,
delegate (Object obj) { return ((String)obj).Length == 5; }
),
delegate (Object obj) { return ((String)obj).ToUpper () ; }
)
);
foreach (string item in expr) {
Console.WriteLine (item);
}
In gewissen Sinne geht also LinQ jetzt schon, nur das die LinQ-Syntax noch knapper und übersichtlicher ist.
herbivore
Ich finde die Erweiterungen eigentlich ziemlich gut. Über Unausgereiftheit würde ich mir weniger Sorgen machen, denn ähnliche Sprachfeatures gibt es schon in anderen Programmiersprachen. Die Iteratoren und die Lambda-Methoden sind ja doch sehr an Python angelehnt.
Auch kann ich mich dem Eisbären anschließen, wenn er sagt, dass es bei C# oft noch an ganz anderen Stellen zwickt. Ich würde hier aber andere Beispiele nennen:
Operatorenüberladung mit generischen Datentypen. Bis heute sind solche Konstrukte in C# ungültig, dass wird sich wohl leider auch mit C# 3.0 nicht ändern:
T x, y, z;
...
public static Vector3<T> operator+(Vector3<T> l, Vector3<T> r)
{
return new Vector3<T>(l.x+r.x,l.y+r.y,l.z+r.z);
}
Außerdem fände ich eine Erweiterung um Multimethoden sinnvoll. Das könnte z.B. das Visitor Pattern überflüssig machen.
I am Jack's smirking revenge.
I am Jack's raging bile duct.
I am Jack's cold sweat.
I am Jack's complete lack of surprise.
I am Jack's broken heart.
I am Jack's wasted life.
Ich bedanke mich für euer bisheriges Engegement für das vielleicht etwas verfrühte Thema.
Und hoffe auf weitere Meinungen.
Selstverständlich hat auch C# schon so ein paar Schwächen(siehe Java-Entwicklung) Erscheinen in direkten Merkmalen nicht so schlimm(Vorteil der späten Geburt?).
Ich find das posten derartiger bereits existierender Mängel aber gut. Inklusive von Meinungen und Bewertungen. Mir selbst gings zwar primär um mögliche künftige Probleme, aber ich finde die Idee ist gut(schiesslich gehts um die Sprache)
@Herbivore
Ich schau es mir noch genauer an. Aber ich hab im Gefühl, dass Iteratoren nicht der Schlüssel sind(Zweifel halt, kein endgültiges(gibts eh nie) Statement).
Als Zwischenstatement möchte ich noch sagen:
Irgendwie ist Linq, eine praktikable Lösung aber ein kleines Bauchgrimmen hab ich schon...
Hallo ikaros,
wenn man sich das o.g. Video anschaut, wird dort aber erst die Iterator-Syntax verwendet. Das ist zwar eine etwas andere Syntax als bei meinen Iteratoren, aber soweit ich das sehe reines C# 2.0. Ich werde - vermutlich nächste Woche - meine Iteratoren mal auf diese Syntax umstellen. Dann wird es vielleicht noch klarer.
Die oben verwendete LinQ-Syntax ist über die Iteratoren gestülpt, so wie die foreach-Syntax über ein schlichtes while gestülpt wurde. Das wir m.E. sogar genau so in dem Video gesagt.
Ich denke mal, dass ist bei der Lamda-Syntax im Vergleich zu den anonymen Methoden aus C# 2.0 nicht anders, also auch nur drübergestülpt.
herbivore
Hallo ikaros,
die Syntax aus dem Video kriegt man mit C# 2.0 annähernd hin. Leider auf Kosten von vielen Methoden in den Iteratoren (jeder Iterator muss dann Where-, Select-, ...-Methoden definieren (kann man natürlich auch in die Oberklasse packen)). Da ich aber mehr als die Iteratoren von LinQ definiert habe, bräuchte ich auch mehr Methoden. Und wenn ein Iterator hinzukommt, muss man jede Interator-Klasse um eine entsprechende Methode erweitern. Mir reicht daher zu wissen wie es geht und ich werde es erstmal nicht umsetzten.
Der Anders Hejlsberg hat es schon gut, dass er nicht nur eigene Klassen sondern eben seine eigene Syntax definieren kann. 🙂
Das man die Syntax aus dem Video nicht ganz genau hinbekommt, liegt an dem neuen Feature von C# 3.0 "Extensions Methods". Damit kann man bestehende Klassen um eigene Methoden erweitern. Schon cool! Der Umstieg auf C#/.NET 3.0 wird vermutlich genauso spannend/nützlich wie der von 1.1 auf 2.0.
herbivore
Ich danke dir erstmal für deine Beiträge. Am Iterator ist also mehr als nur was dran. Das wird mir dann auch helfen sobald ich an die Internas gehe.
>Der Anders Hejlsberg hat es schon gut, dass er nicht nur eigene Klassen sondern >eben seine eigene Syntax definieren kann. 🙂
Was soll man dazu noch hinzufügen? Ist so(den Luxus hätt man manchmal auch gern, bei genauerer Überlegung nicht). So eine Sprache ist wohl die grösste Anwendung(also man programmiert wohl entweder Anwendungen oder Anwendungen von Anwendungen. Nur die Kunden sind anders und die Grösse des Projekts. Stell dir vor deine oder meine Kunden sind auch seine. Sein Projekt ist schon anders. Manchmal, aber nur Manchmal hätt ich auch gern direkten Einfluss..
Damit kann man bestehende Klassen um eigene Methoden erweitern. Schon cool! Der Umstieg auf C#/.NET 3.0
herbivore
Du meinst Vererbung? - 😉
Umstieg auf 3.0:
Vielleicht schaffen da endlich die Objectspaces reinzukommen. Ist mir noch wichtiger als Linq. Allerdings wird Linq wohl zu den Dingen gehören die man niemals wieder vermissen will. Halt noch ein Stück weiter weg von der Datenbank(Abstraktion ohne Aufwand und vielseitig(halt bei allen Collections(oder ähnlichen Gebilden))).
Hallo ikaros,
Du meinst Vererbung?
nein, bei Vererbung kann man nur eine neue Klasse schreiben die neue Methoden enthält. Diese neuen Methoden sind dann aber nur mit Objekten der neuen Klassen benutzbar. Mit Extension Methods wird eine bestehende Klasse um neue Methoden erweitert. Man könnte also die Klasse Strings (ohne deren Autor zu sein) um eine neue Methode (z.B. String.Reverse) erweitern und diese Methode dann für alle Strings verwenden. Wenn ich die Methode in einer von String erbenden Klasse MyString definieren würde, könnte ich sie ja nur für MyString-Objekte verwenden.
herbivore
Ein Extender also(keine Vererbung). Ist aber auch nicht neu. Extenderklassen werden auch gern benutzt(Tooltip-Blasen, ValidatorExtender usw.).
Hallo ikaros,
Extension Methods sind was anderes als Extender-Klassen. Mit Extender Methods kann man Methoden zu einer Klasse hinzufügen, ohne Autor der Klasse sein zu müssen.
herbivore
Hallo Community!
Um meine Meinung beizutragen...
Ich bin grundsätzlich für eine klare Strukturiertheit. Und ich hätte sogar keine Probleme damit, wenn zukünftige .NET-Sprachen absolute Objektorientiertheit vorschreiben würden - sprich: selbst vorherige ValueTypes würden abgeschafft, und es gäbe nur noch Referenzen bzw. Übergabe des Adressraums.
Das wäre eindeutig und sorgte für weniger Missverständnisse bei Umsteigern (vor allem aus dem C'schen Bereich).
Alleinig die ref Anweisung würde entscheiden, ob Parameter "überschreibbar" oder nur "benutzbar/veränderbar" wären - die Adressierungsfrage wäre jedoch einwandfrei geklärt.
Wer je mit wirklichen oo-Sprachen zu tun hatte (s. Ruby), weiss welche Übersicht das mit sich bringt - entweder prozedural oder objektorientiert - eventuelle Zwitterformen sind IMO nicht mehr State of the Art. Hier siegt Strukturiertheit über Effizienz.
Grüsse
Cord
Ich versteh jetzt auf Anhieb nicht den Unterschied. Eine Extender-Klasse fügt(oder überschreibt doch Methoden einer Klasse sie nicht wirklich kennt.
Bsp: wie gesagt Validator und Tooltip(fügen zumindest Methoden hinzu und kennen nur die Basis). TooltipEx(Balloon) überschreibt dann nur die Basis(klassiche Vereebung) des ersten Extenders. Weiter bin ich derzeit nicht. Ein ToolTip kann(als Extender) auf jedenfall die Basisimethoden des Ziels überschreiben. Der Nachfolger von Tooltip könnte als Beispiel aber auch nach bekannten Erweiterungen von Control reagieren. Bekannt dann über allg. Interfaces(die Prüfung von Aggregierten Elementen auf ein Interface ist ja auch nicht so schwer).
Wahrscheinlich ists bei Linq auch ähnlich(glaube ja). Das ein Iterator nach aussen gelegt wird war mir neu(vielleicht geht er auch nicht raus, sondern war Erklärung der Internas(leider immer noch nicht, die Zeit(in vier Wochen hab ich wieder mehr Freizeit, derzeit leider dünn)))
PS:
Ich frag nur nach(geb auch meinen Senf hinzu), will dich aber nicht ärgern. Das sag ich nur, weil du viel beiträgst ich aber(scheinbar) widerspreche.
Beim Eröffnungsposting gings mir auch mehr um die Frage der Syntax. ME findet eine solche statt.
Bin aber Froh wegen des Austauschs um die techn. Sachen.
ikaros
@Cord Worthmann:
Ich bin durchaus für den Smalltalk -Ansatz.
für mich wichtig:
keine Values(das Leben wird wirklich einfacher, auch wenn man sich erst dran gewöhnen muss)
Codeblöcke als Entität. - Einmal geschrieben = wiederverwendbar(einfach nur geklammert)
Edit: ref als Paramter einer Prozedur, wieso? Sehe ich als Rückschritt. Da darf auch kein friend helfen, diese Zugriffe gehören M.E anders geregelt. Rein sprachlich dürfte das nicht möglich sein(ref)(Sprachlich im Sinne von OO inkl. OO(sorry den Begriff find gerade nicht)). Das ref ist einfach nur übel. Ich würde gute Rückgabewerte bevorzugen (objekt neu) das interpretiert werden kann vom Aufrufer(wenns ganz fremd ist). Die Refs bei unkontrollierter Veränderung sehe ich als selten Sinnvoll an. Wobei Sinnvoll und Praxis durchaus kolidieren(ich meine Teams).
ikaros
Hallo ikaros,
Ich versteh jetzt auf Anhieb nicht den Unterschied.
ist es denn wirklich so schwer zu verstehen? Ich hab es doch schon mehrfach beschrieben.
Was müsstest du machen, wenn du in C# 2.0 schreiben wolltest:
String str = "huhu".Reverse ();
Richtig, es geht nicht und du kannst auch keine Klasse schreiben, mit der es geht. (Zur Erinnnerung: die Klasse String definiert keine Reverse-Methode).
Du kannst höchstens eine Unterklasse MyString schreiben, die Reverse definiert. Aber dann kannst du Reverse nur auf Objekte der Unterklasse anwenden, nicht auf Strings selbst. Deshalb habe ich auch im Beispiel oben extra ein String-Literal verwendet, damit das klarer wird.
Mit Extension Methods kann man nun echt die Klasse String erweitern (ohne deren Autor sein zu müssen und ohne den Quell-Code haben zu müssen) und damit wird
String str = "huhu".Reverse ();
möglich.
PS: Ich frag nur nach(geb auch meinen Senf hinzu), will dich aber nicht ärgern. Das sag ich nur, weil du viel beiträgst ich aber(scheinbar) widerspreche.
Gut, ich bin auch nicht wirklich verärgert, nur ein bisschen genervt, weil ich nicht sehe, wo das Problem steckt.
Das ref ist einfach nur übel.
Wo ist dein Problem. Ref ist klar definiert. Es hat auch überhaupt nichts mit unkontrollierter Veränderung zu tun. Ein an eine Methode übergebenes Objekt kann von der Methode ohnehin verändert werden, da auch ohne ref eine Referenz auf das Objekt übergeben wird. Mit ref wird eine Refrenez auf die Refrenz übergeben. Damit kann in der Methode weiterhin das Objekt selbst und zusätzlich die Referenz darauf geändert werden. Wie gesagt: klare Sache. Noch klarer wird es bei out:
obj = M () und M (ref obj) wären gleichwertig. In beiden Fällen würde die "Rückgabe" von M an obj zugewiesen werden.
herbivore
Original von Cord Worthmann
Alleinig die ref Anweisung würde entscheiden, ob Parameter "überschreibbar" oder nur "benutzbar/veränderbar" wären - die Adressierungsfrage wäre jedoch einwandfrei geklärt.
Ähm, genauso ist es doch im Moment.
Ohne ref kannst du nur benutzen/verändern, nur mit ref kannst du überschreiben. Egal ob Wertetyp oder Referenztyp.
Original von Jabberwocky
Ohne ref kannst du nur benutzen/verändern, nur mit ref kannst du überschreiben. Egal ob Wertetyp oder Referenztyp.
Nein. Du musst klar unterscheiden zwischen Werte- und Referenztyp.
Herbivore hats nen Beitrag über deinen erklärt wies bei Referenztypen ist. Es wird immer eine Referenz übergeben und du kannst des Objekt auf das die Referenz verweist ändern wie du lustig bist. Mit ref wird bei Referenztypen eine Referenz auf die Referenz übergeben und dadurch kannst du die Referenz auf das Objekt ändern.
Bei Wertetypen wird normal ne Kopie des Wertes übergeben, der mit dem Ursprungswert nichts mehr gemein hat. Änderungen an der Kopie sind nicht rückwirkend. Mit ref dagegen kannst du direkt auf den übergebenen Wert drauf zugreifen, nicht nur auf die Kopie.
Baka wa shinanakya naoranai.
Mein XING Profil.
Nein, Wertetypen und Referenztypen werden in diesem Aspekt genau gleich behandelt.
Nur gibt es bei Wertetypen keine Änderungen, sie sind unveränderbar und werden deswegen immer neu zugewiesen wenn du etwas "änderst". Deswegen kommen Änderungen nicht Auße an, es gibt sie nämlich nicht.
Das ist der einzige Unterschied und der hat nichts mit dem ref keyword zu tun.
Mir ist klar, dass unter der Haube ein Wertetyp als Kopie übergeben wird. Aber selbst wenn nicht wäre genau das gleiche Verhalten zu beobachten, das ist mein Punkt. Siehe die string Klasse.
Versuche z.B. mal ein foreach über ein Array von structs und "ändere" das struct. Hier wird dir genau dieses Verhalten auf die Füße fallen.
Schau dir mal diesen Artikel ab Seite 2 an, wo ich versucht hab des mitm Heap und Stack zu erläutern und wo Herbivore und svenson ergänzt, bzw. ausgebessert haben. Da wird auch in einem Absatz was zu dem ref gesagt.
Was du da schreibst stimmt so nicht. Wertetypen sind überhaupt nicht unveränderbar. Es wird einfach nur mit einer Kopie gearbeitet! Und das ist auch nicht der einzige Unterschied! Bei Wertetypen wird mit Ref ne Referenz auf die Variable die ja aufm Stack liegt übergeben, und bei Ref mit Referenztypen wird ne Referenz auf die Referenz die auf des Objekt aufm Heap zeigt, übergeben.
Ich würde nicht sagen das dass kein Unterschied ist. Und string als Beispiel anzugeben ist ganz schlecht, weil sich die Klasse in einigen Dingen unterscheidet von einer "Standard"klasse. Sie überschreibt Operatoren um wie ein ValueType zu erscheinen, implementiert deshalb auch noch das IClonable Interface und wird von der CLR noch gesondert behandelt. Das kannst du nicht auf alle Referenztypen verallgemeinern.
Und zu deinem foreach Beispiel. Hast du dich mal informiert wie foreach funktioniert?
In Foreach darf man niemals die Collection über die man iteriert ändern! Das hat nicht mit den Typen zu tun, sondern mit der Implementierung von Foreach. Außerdem iterierst du über ein Array, was also nen ReferenzTyp ist und deren Werte du über die Referenz ändern kannst. Probiers mit ner for Schleife, es geht.
Baka wa shinanakya naoranai.
Mein XING Profil.
Hallo Jabberwocky,
wenn du den qualitativen Unterschied zwischen Werttypen und Referenztypen anerkennst, dann solltest du auch anerkennen, dass ref sich auf Wert- und Refernztypen qualitativ unterschiedlich auswirkt.
Durch ref wird eine Refrenz auf das, was normalerweise übergeben würde, übergeben. Bei Werttypen wird normalerweise ein Wert übergeben. Bei Referenz-Typen wird normalerweise eine Referenz übergeben. Durch ref wird bei Werttypen eine Referenz auf den Wert und bei Referentypen eine Referenz auf die Referenz übergeben. Richtig ist also das durch ref in beiden Fällen eine zusätzliche Referenz ins Spiel kommt. Das ist die Gemeinsamkeit.
Der Werttyp wird aber durch die zusätzliche Referenz quasi zu einem Referenztyp (und das macht gerade den qualitativen Unterschied), wogegen bei einem Referenztypen eine "doppelte" Referenz übergeben wird, was keinen so großen Unterschied mehr macht.
herbivore
class TestClass
{
public int Value;
}
struct TestStruct
{
public int Value;
}
class Programm
{
static void Main()
{
TestClass[] array1 = new TestClass[]{ new TestClass() };
TestStruct[] array2 = new TestStruct[]{ new TestStruct() };
foreach( TestClass c in array1 )
c.Value = 5;
foreach( TestStruct s in array2 )
c.Value = 5;
}
}
Wertetypen sind prinzipiell imutable. Genau dieses verhalten ahmt string nach. Selbst wenn die Übergabe prinzipiell per Referenz funktionieren würde, und ref immer eine Referenz auf eine Referenz übergeben würde (so wie es eben beim String Typ passiert), hast du durch die Unveränderbarkeit exakt das gleiche Verhalten wie im Moment.
Ich bestreite ja garnicht, dass es hinter dem Code unterschiede gibt. Nur wenn man das Verhalten des ref keywords diskutiert, sollte man auch nur das Verhalten betrachten.
Hallo Jabberwocky,
Wertetypen sind prinzipiell imutable.
Das stimmt nicht! Und da das nicht stimmt, sind auch die weiteren Schlussfolgerungen leider alle falsch.
herbivore
Wie erklärst du das foreach Beispiel?
Er versucht s einen neuen Wert zuzuweisen, obwohl ich nur den Inhalt verändert habe.
Ich verstehe die Kritik an den Wertetypen und der Übergabe per "ref" nicht ganz . Wertetypen gibt es aus dem einfachen Grund, dass die Teile viel besser performen als Objekte und vor allem deterministisch arbeiten (kein GC!). So schön Smalltalk auch sein mag, für Aufgabenstellungen wie Cryptographie und Co. würd ichs nicht einsetzen wollen. Auch mal schnell 1 Millionen einzelne Messwerte abholen und verarbeiten macht mit Objekten keinen wirklich Spass, es sei denn man verwendet Objekte wieder, was ein wenig dem ganzen OO-Ansatz wiederspricht.
Die Tatsache, dass MS Wertetypen die Übergabe per Reference spendiert hat (anders als bei Java), mag man aus pädagogischer Sicht bedauern (etwas komplexer als "alles wird by value übergeben"), bringt aber geschickt eingesetzt die Performance, die man für bestimmte Anwendungstypen einfach braucht und erspart einem die Definition von Return-Structs (mehrere Rückgabewerte aus einer Methode).
In der Praxis spielen Wertetypen sowieso eine höchst ungeordnete Rolle. Der "Schutzaspekt", der hier bei "call by value" genannt wurde, sticht insofern nicht. Für Objekte bringt das eh nix (weil ja nur die Referenz by value übergeben wird). Immutable Objektes erfordern einfach viel Handarbeit. Lösungen a la "const" in C++ bringen nix, weil sie nur zur Compile-Time funktionieren, was in dynamischen Systemen wie .NET (PlugIns, Componenten, etc.) maximal der Tropfen auf den heissen Stein sind..
Hallo Jabberwocky,
s ist die "Laufvariable" der foreach-Schleife. Diese darf man nicht ändern. Das hat aber nichts damit zu tun, dass man Werttypen im Allgemeinen nicht ändern darf.
herbivore
Die Laufvariable bei foreach darf man nicht ändern, soweit richtig.
Den Inhalt sehr wohl, das machst du bei Klassen sicher ständig. Auch in dem Beispiel wird das mit einer Klasse gemacht.
Und es wird mit einem Struct versucht. Beim Struct schlägts aber fehl. Warum nur beim struct und nicht bei class?
Hallo Jabberwocky,
weil bei einem Werttyp der Inhalt der Laufvariablen eben der Wert ist.
Bei einem Refrenztyp ist der Inhalt der Laufvariablen die Referenz. Und durch c.Value = 5 wird die Referenz (also der Inhalt der Variable c) nicht geändert.
Durch s.Value = 5 würde der Wert (also der Inhalt der Variable s) geändert werden (was nicht erlaubt ist).
Wenn du c = new TestClass () schreiben würdest, wäre das auch nicht erlaubt, weil es die Referenz (also den Inhalt der Variable c) ändern würde.
herbivore
Original von Jabberwocky
Wie erklärst du das foreach Beispiel?
Einfach weil foreach das nicht erlaubt. Hätte MS aber auch anders implementieren können, wäre aber inkonsistent im Zusammenhang mit Objekten. Wenn Wertetypen immutable wären konnte man z.B. niemals einen Integer-Wert ändern, sondern nur einen neuen Integer erzeugen. Wäre doch höchst ineffizienter Code, oder?
Vielleicht hast du auch gerade noch ein unvollständiges Verständnis wie ein struct im Speicher liegt.
struct ist nur ein Schlüsselwort und hat keine Entsprechung im Speicher. Im Speicher liegen einfach die Variblen hintereinander.
Bei
struct TestStruct
{
public int Value;
}
wären im Speicher nur die 4 Byte für des Value belegt.
Wenn du jetzt in einer foreach Schleife sowas wie
s.Value = 5
schreibst, dann weist du nichts zu, sondern du änderst das komplette struct und das ist wie herbivore schon gesagt hat verboten, man darf die Laufvariable nicht ändern.
Bei Referenztypen ist die Laufvariable ja die Referenz, und die änderst du mit
c.Value = 5;
ja nicht.
Baka wa shinanakya naoranai.
Mein XING Profil.
Hallo Jabberwocky,
das ist ähnlich zu verstehen wie wenn du einen foreach DataRow durch eine DataTable machst. Da dürfen die Rows auch nicht verändert werden. Oder bin ich da jetzt ganz falsch? Habs nicht so mit structs X(
Es ist toll jemand zu sein, der nichts von der persönlichen Meinung Anderer hält. - frisch-live.de
Hallo frisch,
wenn ich richtig verstehe, was du meinst, dann ist das was anderes. Bei foreach darf die zugrundeliegende Collection nicht geändert werden. Hier ginge es aber um die Änderung der Laufvariable.
herbivore
Ach ihr meint z.B. folgendes:
for(int i = 0; i < 5; i++) {
if(i > 2) i = 0;
}
Es ist toll jemand zu sein, der nichts von der persönlichen Meinung Anderer hält. - frisch-live.de
Hallo frisch,
nö, wir meinen schon foreach, aber das auch nur im Zusammenhang mit Wert- vs. Referenztypen.
herbivore
@herbivore:
ich bezog auf ExtenderKlassen. Vielleicht haben wir aneinander vorbei gelabert...
Die Funktionsbeschreibung liess sich m.E. über eine Extentender- Klasse lösen.
Das Erweitern von Methoden in 2.0 ist mir so unbekannt. Ein MethodenExpander als Sprach- oder FCL erweiterung?
Hallo ikaros,
es ging natürlich um C# 3.0. Hast du denn schon mal das channel9-Video gesehen? Ich beziehe mich ja einfach nur, auf das was Anders Hejlsberg dort beschreibt, als er sagt, warum er customers.Where (...) schreiben kann.
herbivore
>channel9-Video
Nö noch nicht(Wann?). Hab bisher ein paar Artikel gelesen und will demnächst(wohl erst in 4 Wochen) damit rumspielen(die Vorabversion gibts zum Download).
Dann versuch ich auch mal ein paar Klassen zu reflektieren(Neugierig halt).