Benutzer mit den meisten Antworten
Rückgabeparameter für LINQ-Abfrage ?

Frage
-
Hallo
ich habe folgende LINQ-Abfrage
var list = (from p in this.GetBaseQuery() select new { p.MemoNotPresent }).Distinct().ToList();
"p.MemoNotPresent" ist ein string. Jetzt habe ich das Problem, dass ich diese Abfrage in eine Methode verpacken möchte, und ich dachte mir einfach den RückgabeParameter der Methode wie folgt zu deklarieren:
public IEnumerable<string> RetrieveAbwesenheitsGruende() {
aber leider funktioniert das nicht - hier lässt mich der Compiler schon nicht mehr weiter; dann hätte ich gedacht ich baue das auf ein List<string> um - aber auch hier scheitere ich.
Welchen RückgabeParameter kann/muss ich denn für diese einfach LINQ-Abfrage deklarieren ?
Kann mir dazu bitte jemand einen Rat geben.
Danke & schönen Gruß
Michael
Michael Erlinger
Antworten
-
Hallo Michael,
ich gehe davon aus MemoNotPresent ist vom Typ String.
Dann lass das new weg, denn damit erzeugst Du eine (anonyme) Klasse, die Du gar nicht willst:
sollte dann einen List<String> enthalten.var list = (from p in this.GetBaseQuery() select p.MemoNotPresent).Distinct().ToList();
Gruß Elmar
- Als Antwort markiert Robert BreitenhoferModerator Dienstag, 18. Januar 2011 09:29
-
Hallo Michael,
man kann auch trotzdem mit new arbeiten, und hat dann einen anonymen Typ. ich habe natürlich auch nichts gegen die Variante ohne new, aber das ist beides möglich. Als Rückgabe benutzt man dann um Beispiel: IEnumerable<object>
Das sieht dann zum Beispiel so aus:public Form1() { InitializeComponent(); var res = Test(); } IEnumerable<object> Test() { var list = (from p in this.GetBaseQuery() select new { p.MemoNotPresent }).Distinct().ToList(); return list; } // nur als Beispiel: public ObjectSet<Mitglied> GetBaseQuery() { var mitglieder = new DemoEntities().CreateObjectSet<Mitglied>(); return mitglieder; }
[siehe auch die kommende Anmerkung]
ciao Frank- Bearbeitet Frank Dzaebel Mittwoch, 15. Dezember 2010 16:01
- Als Antwort markiert Robert BreitenhoferModerator Dienstag, 18. Januar 2011 09:31
-
Ich habe noch nicht ganz herausgefunden, wann bei einer LINQ-Abfrage "new" verwendet werden soll, und wann nicht.....??
Das "new" nimmst du am besten nur dann, wenn du einen neuen Datentyp erzeugen musst, also wenn du eine neue Instanz wirklich brauchst. Also wenn du nur einen Wert zurücklieferst, dann kannst du den direkt zurückliefern. Wenn du aber mehrere Werte zurückliefern willst, dann brauchst du dafür einen Datentyp in den du die zusätzlichen Informationen reinstopfen kannst. Den Datentyp kannst du dann selbst definieren (Wie "blubb" oben), oder einfach einen anonymen Datentyp erzeugen:
var list = (from p in this.GetBaseQuery() select new { A = p.MemoNotPresent, Len = p.MemoNotPresent.Length }) .Distinct().ToList();
- Als Antwort markiert Robert BreitenhoferModerator Dienstag, 18. Januar 2011 09:31
-
So wie du es gemacht hast geht das nicht. Du erzeugst mit
select new { p.MemoNotPresent }
einen neuen anonymen Datentyp, den du selbst gar nicht angeben kannst. Schliesslich ist es ein anonymer Datentyp... Du müsstest dann den Datentyp vorher selbst definieren:
class blubb { public string s; } //... var list = (from p in this.GetBaseQuery() select new blubb(){ s=p.MemoNotPresent }).Distinct().ToList();
Ich kann jedoch nicht erkennen, WARUM du überhaupt einen neuen Datentyp erzeugst:
Das sollte es nämlich auch tun. Damit müsste dann List<string> funktionieren.var list = (from p in this.GetBaseQuery() select p.MemoNotPresent).Distinct().ToList();
- Als Antwort markiert Robert BreitenhoferModerator Dienstag, 18. Januar 2011 09:29
Alle Antworten
-
Hallo Michael,
ich gehe davon aus MemoNotPresent ist vom Typ String.
Dann lass das new weg, denn damit erzeugst Du eine (anonyme) Klasse, die Du gar nicht willst:
sollte dann einen List<String> enthalten.var list = (from p in this.GetBaseQuery() select p.MemoNotPresent).Distinct().ToList();
Gruß Elmar
- Als Antwort markiert Robert BreitenhoferModerator Dienstag, 18. Januar 2011 09:29
-
So wie du es gemacht hast geht das nicht. Du erzeugst mit
select new { p.MemoNotPresent }
einen neuen anonymen Datentyp, den du selbst gar nicht angeben kannst. Schliesslich ist es ein anonymer Datentyp... Du müsstest dann den Datentyp vorher selbst definieren:
class blubb { public string s; } //... var list = (from p in this.GetBaseQuery() select new blubb(){ s=p.MemoNotPresent }).Distinct().ToList();
Ich kann jedoch nicht erkennen, WARUM du überhaupt einen neuen Datentyp erzeugst:
Das sollte es nämlich auch tun. Damit müsste dann List<string> funktionieren.var list = (from p in this.GetBaseQuery() select p.MemoNotPresent).Distinct().ToList();
- Als Antwort markiert Robert BreitenhoferModerator Dienstag, 18. Januar 2011 09:29
-
Hallo
danke Euch beiden für die rasche Rückmeldung!!
Stimmt - ohne dem "select new {...}" in der LINQ-Abfrage funktioniert es - ich kann auch IEnumberable<string> als RückgabeParameter nehmen.
Ich habe noch nicht ganz herausgefunden, wann bei einer LINQ-Abfrage "new" verwendet werden soll, und wann nicht.....??
Schönen Gruß
Michael
Michael Erlinger -
Hallo Michael,
Das liegt am anonymen Typ, den Du erzeugst. Probier's mal so:
using System; using System.Linq; using System.Collections.Generic; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { MyQueryClass query = new MyQueryClass(); var q = query.RetrieveAbwesenheitsGruende(); foreach (var s in q) Console.WriteLine(s); Console.ReadKey(true); } } class BaseQuery { public string MemoNotPresent { get; set; } } class MyQueryClass { List<BaseQuery> list = new List<BaseQuery> { new BaseQuery { MemoNotPresent = "new row" }, new BaseQuery { MemoNotPresent = "deleted" } }; public List<BaseQuery> GetBaseQuery() { return list; } public IEnumerable<string> RetrieveAbwesenheitsGruende() { var query = (from p in this.GetBaseQuery() select p.MemoNotPresent).ToList(); return query; } } }
Gruß
Marcel -
Hallo Michael,
man kann auch trotzdem mit new arbeiten, und hat dann einen anonymen Typ. ich habe natürlich auch nichts gegen die Variante ohne new, aber das ist beides möglich. Als Rückgabe benutzt man dann um Beispiel: IEnumerable<object>
Das sieht dann zum Beispiel so aus:public Form1() { InitializeComponent(); var res = Test(); } IEnumerable<object> Test() { var list = (from p in this.GetBaseQuery() select new { p.MemoNotPresent }).Distinct().ToList(); return list; } // nur als Beispiel: public ObjectSet<Mitglied> GetBaseQuery() { var mitglieder = new DemoEntities().CreateObjectSet<Mitglied>(); return mitglieder; }
[siehe auch die kommende Anmerkung]
ciao Frank- Bearbeitet Frank Dzaebel Mittwoch, 15. Dezember 2010 16:01
- Als Antwort markiert Robert BreitenhoferModerator Dienstag, 18. Januar 2011 09:31
-
Ich habe noch nicht ganz herausgefunden, wann bei einer LINQ-Abfrage "new" verwendet werden soll, und wann nicht.....??
Das "new" nimmst du am besten nur dann, wenn du einen neuen Datentyp erzeugen musst, also wenn du eine neue Instanz wirklich brauchst. Also wenn du nur einen Wert zurücklieferst, dann kannst du den direkt zurückliefern. Wenn du aber mehrere Werte zurückliefern willst, dann brauchst du dafür einen Datentyp in den du die zusätzlichen Informationen reinstopfen kannst. Den Datentyp kannst du dann selbst definieren (Wie "blubb" oben), oder einfach einen anonymen Datentyp erzeugen:
var list = (from p in this.GetBaseQuery() select new { A = p.MemoNotPresent, Len = p.MemoNotPresent.Length }) .Distinct().ToList();
- Als Antwort markiert Robert BreitenhoferModerator Dienstag, 18. Januar 2011 09:31
-
Hallo Michael,
Zur Sicherheit - Du kannst hier auch new verwenden. Man verwendet new häufig, wenn man es als Typ haben möchte, beispielsweise, wenn man auch mehrere Eigenschaften hat. Dann ist das Handling hier einfacher. In einer öffentlichen Klassenbibliothek wird man allerdings normal keine anonymen Typen nach außen geben - also nur für internen Übergaben benutzen!
[Anonyme Typen (C#-Programmierhandbuch)]
http://msdn.microsoft.com/de-de/library/bb397696.aspx
ciao Frank -
Hallo Michael,
Du solltest Dir durchlesen, was ein anonymer Typ ist =>
Letztendlich nichts weiter als eine Klasse, die der Compiler Dir im Hintergrund erstellt.Bei öffentlichen Datenbankschnittstellen, um die es hier wohl geht, sind sie i. a. tabu,
da sie nicht für den öffentlichen Gebrauch gedacht sind, sondern nur für lokale
Verarbeitungsschritte innerhalb einer Methode .Dort würde man eine öffentliche Klasse erstellen, i. a. als Data Transfer Object (DTO)
bezeichnet, und für die Projektion bekannt machen, so dass sie von aussen zugänglich ist.Siehe auch: http://stackoverflow.com/questions/1440289/initializing-strongly-typed-objects-in-linq-to-entities
http://stackoverflow.com/questions/3646266/avoiding-repeated-projection-code-in-entity-frameworkGruß Elmar
- Bearbeitet Elmar BoyeEditor Donnerstag, 16. Dezember 2010 16:41 drei Worte gestrichen
-
Hallo Elmar,
> öffentlichen Datenbankschnittstellen, um die es hier wohl geht, sind
> sie i. a. tabu [anonyme Typen] ...Man kann auch bei öffentlichen Datenbankschnittstellen anonyme Typen verwenden, wenn diese nur für interne Methoden-Übergaben (etwa für Zwischen-Rechnungen) benutzt werden. Sie sind nicht auf "innerhalb einer Methode" beschränkt. Es ist ja nur gesagt, dass eine "Abfrage in eine Methode verpackt werden soll", was durchaus intern sein kann.
Bei öffentlichen Klassenbibliotheken werden anonyme Typen normal nicht in Methoden übergeben.> Dort würde man eine öffentliche Klasse erstellen ...
Dort "kann" man das machen. Sowas geht aber nicht immer, gerade in dynamischen Szenarien. Und in diesen haben die anonymen Typen oft ihre Vorteile - es ist letztlich beides eine "Möglichkeit".
ciao Frank- Bearbeitet Frank Dzaebel Mittwoch, 15. Dezember 2010 13:48
-
Elmar,
erstens - sieht man Dein Zitat ja im vorangehenden Posting, und die "[...]" besagen das ja. Das intelligente Quoting hat sich IMHO eigentlich überall durchgesetzt... zum Beispiel:
[Wie zitiere ich im Usenet? - Zitieren und antworten]
http://www.afaik.de/usenet/faq/zitieren/zitieren-2.php3#ss2.1- Es ist nicht nötig, den gesamten Text des Vorredners zu zitieren. Zitate sollen in erster Linie einen Bezugspunkt darstellen, der den Mitlesenden einen schnellen Wiedereinstieg in den Thread ermöglicht. Sie sind nicht dazu gedacht, den vorangegangenen Artikel noch einmal zu veröffentlichen.
________________
Deine Aussage: "sondern nur für lokale Verarbeitungsschritte innerhalb einer Methode" sehe ich wie gesagt anders. Besonders in dynamischen internen Szenarien kann man - wie gesagt - Vorteile durch Übergabe von anonymen Typen haben.
ciao Frank -
Hallo Elmar,
> dynamischen internen Szenarien ... sind was?unter anderem, wenn der Übergabe-Typ nicht im Code bekannt ist, oder nicht bekannt gemacht werden soll/kann, oder der Aufwand dafür unangemessen ist. Im Prinzip in Teilen analog zu den Szenarien, wo man auch mit dynamic Linq o.ä. arbeitet (nur in dem Fall typsicherer), oder zu Szenarien, bei denen man mit dynamic arbeitet. Und "Intern" heisst, dass man diese Methoden nicht als Schnittstelle nach aussen zulässt (hier sind wir ja einer Meinung), also deren Modifizierer oft "private" o.ä. ist.
Allgemein wird man auch in Szenarien, wo man bereits anonyme Typen hat, nicht unbedingt intern immer ständig in Listen umwandeln (kostet auch Performance und Speicher) sondern natürlich diese Typen eben weiterverwenden, sonst hätte man sich diese nicht erst erstellt. Und das es Szenarien gibt, wo anonyme Typen sinnvoll eingesetzt und weiterbenutzt werden können, ist sicher unstrittig.
ciao Frank- Bearbeitet Frank Dzaebel Mittwoch, 15. Dezember 2010 13:46
-
Hallo Elmar,
> und das steht jetzt wie im Zusammenhang mit öffentlichen Datenbankschnittstellen???
logischerweise eher auf den zweiten Teil Deiner Aussage (um den es ja jetzt ging):
" ... da sie nicht für den öffentlichen Gebrauch gedacht sind, sondern
nur für lokale Verarbeitungsschritte innerhalb einer Methode.".. den ich ja anders sehe:
-> sie können sinnvoll/vorteilhaft auch in Methoden übergeben werden
und brauchen nicht nur innerhalb einer Methode benutzt werden.
ciao Frank -
Hallo Frank,
Danke, dass Du jetzt auch auf den zweiten Teil der bisher ausgelassenen Aussage eingehst.
Ich verstehe jedeoch nicht, was unterscheidet
... auch in Methoden übergeben werden...
von
... innerhalb einer Methode benutzt werden .
ganz davon abgesehen, was daran jetzt öffentlich sein soll.
Gruß Elmar
- Bearbeitet Elmar BoyeEditor Mittwoch, 15. Dezember 2010 15:09 Format
-
Elmar,
> dass Du jetzt auch auf den zweiten Teil der bisher ausgelassenen Aussage eingehst
bin ich die ganze Zeit, aber Du hattest evtl. missverstanden, weil Du die Form des Zitates mit den Auslassungszeichen anders interpretiert hattest.
- > Ich verstehe jedeoch nicht, was unterscheidet
> ... auch in Methoden übergeben werden...
> von
> ... innerhalb einer Methode benutzt werden .
machen wirs mal anders herum, was willst Du denn mit "innerhalb einer Methode" ausdrücken?
Wenn Du meinst, dass die "Übergabe von anonymen Typen" für Dich in Frage kommt, sind wir einer Meinung! Wenn Deine Aussage syntaktisch gemeint wäre, wäre Deine Aussage ja unrichtig, da es auch die Möglichkeit gibt anonyme Typen nicht innerhalb von Methoden zu benutzen .. etwa:
object s = new { Name = "Alpha", Alter = 42 }; // als Feld
> was daran jetzt öffentlich sein soll.mir kommt Deine Frage sehr trivial vor, also ist sie sicher anders gemeint, als ich sie verstehe.
Es gibt öffentliche und nicht öffentliche Methoden.
Wenn Du Methoden öffentlich (public) machst, kann man sie von außen ansprechen, was im Falle von anonymen Typen (als Parameter) zu überdenken ist. Das ist mit öffentlich gemeint.
ciao Frank - > Ich verstehe jedeoch nicht, was unterscheidet
-
Hallo Frank,
was die Auslassungen angehst, sollte Dir klar dann langsam sein, warum ich Verkürzungen nicht mag.
Entweder man zitiert das, was man zu kommentieren möchte -- oder man tut es gar nicht
(schliesslich sind wir hier in einem Forum - und nicht im Usenet).Und leider kann ich nicht anders herum ... ausdrücken , da ich den Sinn und Zweck
Deiner Ausführungen bis jetzt nicht vollständig folgen kann.Meine Aussage bezieht sich von Anfang an darauf, dass
anonyme Typen nicht in öffentlichen Schnittstellen verwende t werden sollten.Und Du hast ja auch mehrfach erläutert wieso das keine gute Idee ist -
soviel Einigkeit glaube ich herauslesen zu können.Inwieweit sie innerhalb einer Klasse erzeugt, als lokale oder als Instanzvariablen gespeichert,
innerhalb oder zwischen Methoden übergeben werden - und alles andere, was man mit einer Klasse,
sei sie anonym oder nicht anstellen kann, ist dafür meines Erarchtens nicht von Belang.Und so fehlt mir die fachliche Erklärung, welchen Unterschied Du mit Deinen Beiträgen herausarbeiten willst.
Gruß Elmar
-
Hallo Elmar,
> Auslassungen
vielleicht solltest Du Dir ja auch einmal die Verwendung von Zitaten und deren Sinn vergegenwärtigen, dessen Essenz ganz unabhängig vom UseNet gültig ist:
[Wie zitiere ich im Usenet? - Zitieren und antworten]
http://www.afaik.de/usenet/faq/zitieren/zitieren-2.php3#ss2.1- Es ist nicht nötig, den gesamten Text des Vorredners zu zitieren. Zitate sollen in erster Linie einen Bezugspunkt darstellen, der den Mitlesenden einen schnellen Wiedereinstieg in den Thread ermöglicht. Sie sind nicht dazu gedacht, den vorangegangenen Artikel noch einmal zu veröffentlichen.
Trotzdem respektiere ich natürlich Deine Einstellung dazu.
_______________________
Mein fachliches Resumee:- "Übergabe von anonymen Typen über Parametern an andere Methoden" sind durchaus sinnvoll, wenn es einen Vorteil bringt und dieses nicht in öffentlichen Methoden passiert.
Hier sollten wir IMHO enden - eine Zitat-Diskussion würde ich ins Off-Topic verschieben, da es hier keine technischen Inhalt hat.
ciao Frank -
Hallo Frank,
Zum fachlichen: Da Du keine Unterschiede und meiner Empfehlung nicht widersprichst,
sehe ich das Thema als abgeschlossen an.Zu Deinem wiederholten Zitat: Wir sind immer noch nicht im UseNet (so sehr ich es geschätzt habe).
Wenn Du dies wiederholt heranziehen willst, so steht dort auch:- Auf der anderen Seite sollte ein Zitat nicht so knapp ausfallen, daß die Aussage
des Autors unklar wird oder gar in einem völlig anderen, falschen Licht erscheint
Und die Höflichkeit gebietet es, wenn der Zitierte sich so dargestellt sieht, dem Genüge zu leisten.
Gruß Elmar - Auf der anderen Seite sollte ein Zitat nicht so knapp ausfallen, daß die Aussage
-
Hallo Elmar,
hättest Du das eher gesagt, dass Du meiner Meinung bist (so höre ich es jetzt heraus), also:
- ("Übergabe von anonymen Typen über Parametern an andere Methoden" sind durchaus sinnvoll, wenn es einen Vorteil bringt und dieses nicht in öffentlichen Methoden passiert.)
hätte man sich ggf. viel Zeit gespart.
Und wie gesagt, Zitat-Themen würde ich eher im Off Topic diskutieren, wenn es geht.
Das Du das UseNet schätztest - ging mir auch so, aber ich muss sagen, die Foren finde ich klar besser - ist aber wieder ein off Topic ;-)
Und wie gesagt, nicht nur im UseNet gilt die Essenz:- Es ist nicht nötig, den gesamten Text des Vorredners zu zitieren. Zitate sollen in erster Linie einen Bezugspunkt darstellen, der den Mitlesenden einen schnellen Wiedereinstieg in den Thread ermöglicht. Sie sind nicht dazu gedacht, den vorangegangenen Artikel noch einmal zu veröffentlichen.
Und zu:
- Auf der anderen Seite sollte ein Zitat nicht so knapp ausfallen, daß die Aussage
des Autors unklar wird oder gar in einem völlig anderen, falschen Licht erscheint
das sehe ich genauso - wenn Du meine Postings anschaust - ich zitiere immer so und keiner hat seit 12000 Postings dies hier mal nicht verstanden (sicher gibt es Ausnahmen). Aber wenn ich weiss, dass man bei Dir halt immer komplett zitieren sollte, weil das sonst für Dich ein Angriff ist, dann kann ich das gerne bei Dir so machen (versuchen). Ein bißchen Rücksicht kann nicht schaden.
So, jetzt sollten wir aber entweder im OffTopic weiterdiskutieren oder hier die Postings löschen, da jetzt langsam nichts Technisches mehr drin ist.
ciao Frank -
Hallo Frank,
was Du daraus hören willst, kann ich nicht nicht lesen.
Deine wiederholte Aussage trägt meiner Auffassung nichts zu meiner Aussage bei,
wo es um öffentlichen Schnittstellen geht - aber belassen wir es dabei.Und ich bedanke mich im voraus, dass Du mich in Zukunft vollständig
und ohne Auslassungen zitieren wirst (bzw. es versuchen).Gruß Elmar
-
Elmar schrieb im Beitrag:
folgendes:
Hallo Frank,
was Du daraus hören willst, kann ich nicht nicht lesen.
Deine wiederholte Aussage trägt meiner Auffassung nichts zu meiner Aussage bei,
wo es um öffentlichen Schnittstellen geht - aber belassen wir es dabei.Und ich bedanke mich im voraus, dass Du mich in Zukunft vollständig
und ohne Auslassungen zitieren wirst (bzw. es versuchen).Gruß Elmar
Hallo Elmar,
ist zwar Aufwand und unübersichtlich IMHO, aber es ist dann ja nur bei einem.
_________________
Dann ist meine persönliche fachliche Quintessenz jedenfalls, die Du also nicht vertritts:- "Übergabe von anonymen Typen über Parametern an andere Methoden" sind durchaus sinnvoll, wenn es einen Vorteil bringt und dieses nicht in öffentlichen Methoden passiert.
Belassen wir es also dabei.
ciao Frank -
Hallo Frank,
wenn Du das als Deine Quintessenz bezeichnest, so sei es Dir belassen, wenn Du damit etwas gelernt hast.
Zum Zitieren: Zum einen muss hier niemand zitieren .
Zum anderen habe ich darum gebeten , wenn so zu zitieren, dass das Zitat verständlich ist -
von Fullquotes war niemals die Rede.Gruß Elmar
-
Elmar,
Du lenkst hier den Thread immer wieder in unfachliche Themen, wie die Art des Zitierens.
Dazu sage ich jetzt, ich zitiere weiter so, wie ich es immer gemacht habe. Ggf. auch mit Auslassungszeichen, wenn klar ist, welcher Satz gemeint ist (was hier der Fall ist).
Dabei benutze ich ich diese Herangehenweise und Grundprinzipien. Wenn trotzdem etwas unklar ist, muss derjenige nachfragen und ich erkläre ihm ggf. notwendiges.
Für mich hat das die meisten Vorteile.
Wir können hier auch per privater Mail einmal Vor- und Nachteile der ein oder anderen Art austauschen, oder in der Off-Topic Gruppe diskutieren, aber hier ist das der falsche Platz.So jetzt nochmal meine technische Essenz:
- "Übergabe von anonymen Typen über Parametern an andere Methoden" sind durchaus sinnvoll, wenn es einen Vorteil bringt und dieses nicht in öffentlichen Methoden passiert.
Es gibt auch die Möglichkeit anonyme Typen nicht innerhalb von Methoden zu benutzen .. etwa:
object s = new { Name = "Alpha", Alter = 42 }; // als Feld
ciao Frank -
Hallo Frank,
ich freue mich, dass Dir Deine Essenz so gut gefällt, das Du sie immer wiederholst.
Auch wenn sich mir nicht erschliesst, welchen Mehrwert sie für das behandelte Thema hat.Ich habe darum gebeten korrekt zitiert zu werden, und werde darauf auch in Zukunft bestehen.
Wenn Du Fragen zum richtigen Zitieren hast, steht es Dir frei im dafür vorgesehenen Forum
zu stellen, die Forums-Moderation wird dabei sicherlich weiterhelfen.Gruß Elmar
-
Elmar,
es steht Dir frei, Dich in Off Topic Forum über Zitieren zu informieren - aber bitte nicht hier!
Selber scheinst Du jetzt auch nicht mehr zu zitieren.
Da keine fachlichen Einwände kamen, nehme ich die folgendes Posting als fachliche Essenz.
ciao Frank -
-
Hallo Frank,
Hallo Elmar,Fachliche Einwände sind oft schwer ohne Code nachzuvollziehen. Deshalb nachfolgender Code (4.0):
using System; using System.Collections.Generic; using System.Linq; using System.Reflection; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { try { string result = ProblemsFactory.DoSolveAllProblems(); Console.WriteLine(result); } catch (Exception ex) { Console.WriteLine("ERROR: {0}", ex.Message); } Console.ReadKey(true); } } class ProblemsFactory { static string[] stringProblems = new string[] { "one", "two", "three" }; static int[] intProblems = new int[] { 1, 2, 3 }; static object[] objProblems = new object[] { new object(), new object(), new object() }; static Person[] personProblems = new Person[] { new Person { FirstName = "John", LastName = "Doe" }, new Person { FirstName = "Jane", LastName = "Doe" } }; private static IEnumerable<object> GetListOfProblems() { Random random = new Random(DateTime.Now.Millisecond); int randomIndex = random.Next(0, 4); switch (randomIndex) { case 0: var query1 = from s in stringProblems select new { Problem = s }; return query1; case 1: var query2 = from i in intProblems select new { ProblemID = 52, Problem = i }; return query2; case 2: var query3 = from o in objProblems select new { Issue = o }; return query3; case 3: var query4 = from p in personProblems select new { LastName = p.LastName }; return query4; } return null; } private static string Solve(IEnumerable<object> problemsList) { Type[] genericArguments = null; foreach (var s in problemsList) { if (genericArguments == null) genericArguments = s.GetType().GetGenericArguments(); if (genericArguments[0] == typeof(string)) { Console.WriteLine("Solving a string problem for {0}", CastAnonymousTypeByExample(s, new { Problem = String.Empty }).Problem); } else { if (genericArguments[0] == typeof(int)) { Console.WriteLine("Solving a integer problem for {0}", CastAnonymousTypeByExample(s, new { Problem = 0 }).Problem); } else { if (genericArguments[0] == typeof(object)) { try { Console.WriteLine("Solving an object problem for {0}", CastAnonymousTypeByExample(s, new { Problem = new object() }).Problem); } catch (InvalidCastException) { Console.WriteLine("No problem, just an issue.\nSolving an object issue for {0}", CastAnonymousTypeByExample(s, new { Issue = new object() }).Issue); } } } } } return "Solving done (at least I think so)."; } private static T CastAnonymousTypeByExample<T>(object anonymous, T typeExpression) { return (T)anonymous; } public static string DoSolveAllProblems() { IEnumerable<object> listOfProblems = GetListOfProblems(); string result = Solve(listOfProblems); return result; } } class Person { public string FirstName { get; set; } public string LastName { get; set; } } }
Es würde mich sehr interessieren, wie ihr dazu steht, das von GetListOfProblems zurückgegebene IEnumerable<object> innerhalb der Klasse ProblemsFactory zu verwenden.
Gruß
Marcel -
Hallo Marcel,
kurz zum Effekt Deines Code-Beispiels - für andere Mitleser.
Es gibt ja eine (sicher gewollte) Exception, beim Casting.
Nun fragst Du ja folgendes:- > Es würde mich sehr interessieren, wie ihr dazu steht, das von GetListOfProblems
> zurückgegebene IEnumerable<object> innerhalb der Klasse ProblemsFactory zu verwenden.
Also das Benutzen und Übergeben der anonymen Typen (an private Methoden) ist ja in Ordnung.
Nur - es gilt auch das, was auch immer für object gilt - ich vereinfache mal:object o1 = 42; object o2 = (string)o1; // natürlich eine Exception
Das Problem liegt ja in Deiner "CastAnonymousTypeByExample" Methode.
Als allgemeine Richtlinie empfehle ich immer, so typsicher wie möglich zu arbeiten - aber es gibt Szenarien, in denen auch dynamische Typen sinnvoll zum Einsatz kommen.
IEnumerable<object> enthält aber eine Liste von objekt. Dass mit object falsch gecastet werden "kann", ist ja nichts neues. Dass das auch für Listen von object gilt, liegt auf der Hand.
Das sind so meine Bemerkungen/Ideen, die ich zu Deinem Code-Beispiel hätte.
ciao Frank - > Es würde mich sehr interessieren, wie ihr dazu steht, das von GetListOfProblems
-
Hallo Frank,
Also das Benutzen und Übergeben der anonymen Typen (an private Methoden) ist ja in Ordnung [...]
Rein technisch gesehen: JA. Aber ich frage mich, wo liegt der Sinn? Eigentlich könnte man doch eine stark typisierte List<T> auch direkt an Solve(IEnumerable<object) übergeben. Dazu muss man keine anonymen Typen jenseits von Methodengrenzen exportieren. Und Solve() wäre dank IEnumerable<object> noch immer in der Lage, multiple Listentypen zu verarbeiten, diesmal ohne die mit den anonymen Typen verbundenen Probleme (Typ- und Propertyidentität, Cast, Zugriff auf Member etc.) kompliziert lösen zu müssen. Zudem wäre der Code pflegeleichter.
Das Problem liegt ja in Deiner "CastAnonymousTypeByExample" Methode [...]
Dieser bekannte Notbehelf ist auf die Verwendung anonymer Typen zurückzuführen und zeigt wie anfällig die Arbeit mit anonymen Typen tatsächlich ist. BTW: Kennst Du eine andere Methode, anonyme Typen zu inferieren, so dass man auf sie und ihre Eigenschaften *sicher* zugreifen kann?
Gruß
Marcel -
Hallo Marcel,
- > Rein technisch gesehen: JA. Aber ich frage mich, wo liegt der Sinn? Eigentlich könnte man doch eine stark typisierte List<T> auch direkt an Solve(IEnumerable<object)
sicher, man "kann" das, aber in Situationen, wo man bereits anonyme Typen hat, wäre ist es ggf. performancemäßig und vom Speicherverbrauch ggf. unangebracht, diese in stark typisierte List<T> zu überführen. Man bildet dann ja normal neue Instanzen, was bei der reine Übergabe in Methoden nicht passiert. "Dass" man wiederum ggf. vorteilhaft in Methoden kapselt, ergibt sich ja bereits aus Strukturierungsprinzipien. Und dass man mit anonymen Typen selber überhaupt arbeitet, ist ja sicher auch nicht kontrovers. Es ist also beides je nach Szenario möglich und ggf. auch gut. Aber- im Prinzip schon, wie ich vorhin sagte - m.E. ähnlich zu object-Nutzungs-Szenarien.
- > zeigt wie anfällig die Arbeit mit anonymen Typen tatsächlich ist.
zum Teil sicher, aber ich sehe das etwas weniger stark, als das in Deiner Formulierung den Anschein hat. Anonyme Typen sind .NET Typen und quasi typsicher, und wenn man den einen in den anderen casten will, kommt saubererweise eine Exception. Dass man sie nicht "sieht" kann natürlich in der einen oder anderen Situation eher zu Fehlern führen. Aber man benutzt sie ja in bestimmten Situationen, um gewisse Vorteile zu erreichen, die dann Nachteile ggf. überwiegen können.
- BTW: Kennst Du eine andere Methode, anonyme Typen zu inferieren, so dass man auf sie und ihre Eigenschaften *sicher* zugreifen kann?
ok, "inferieren" ... Du meinst also einen anonymen Typ in einen früh gebundenen Typ abzuleiten/projezieren/umzuwandeln. Dein Ausdruck "*sicher*" ist wohl noch näher zu definieren, aber man kann zum Beispiel auch folgende Ansätze oder Erweiterungsmethoden benutzen:
- http://www.codeproject.com/KB/linq/AnonymousTypeTransform.aspx
- Resharper kann auch anonymous Type refactoring - also als IDE-Feature.
- http://www.comanswer.com/question/how-can-i-convert-anonymous-type-to-ttype
ciao Frank -
Hallo Frank,
> aber in Situationen, wo man bereits anonyme Typen hat, wäre ist es ggf. performancemäßig und vom Speicherverbrauch ggf. unangebracht, diese in stark typisierte List<T> zu überführen
Ich meinte stark typisierte List<T> statt anonyme Typen. Von Anfang an. Wo ich new { Problem=p.LastName } schreibe, kann ich doch gleich new PersonProblem { Problem=p.LastName } nehmen. Das wäre doch vom Speicherverbrauch vergleichbar, und bei der Auswertung in Solve(IEnumerable<object>) würde die ganze Reflection bzw. das casting by example entfallen, die man zum Umwandeln des anonymen Typs braucht, was der Performance auch nicht schaden würde.
Marcel schrieb: [...] zeigt wie anfällig die Arbeit mit anonymen Typen tatsächlich ist
Frank schrieb: Ich sehe das etwas weniger stark [...]. Anonyme Typen sind .NET Typen und quasi typsicher, und wenn man den einen in den anderen casten will, kommt saubererweise eine Exception.Also ich habe folgende Probleme mit anonymen Typen, die über Methodengrenzen hinaus exportiert werden:
- Identitätsverlust: new {Problem="A"} ergibt den gleichen anonymen Typ wie new {Problem="B"}. Bei stark typisierten Klassen ist jedoch ClassA.Problem durchaus was anderes als ClassB.Problem (wenn zwischen den Klassen keine Vererbungsbeziehung existiert).
- Komplexe Differenziierung: In der Ziel-Methode, in meinem Beispiel Solve(IEnumerable<object>), muss die Ablauflogik zwischen den einzelnen anonymen Typen als sinngebende Einheiten unterscheiden. Das schafft aber - angesichts der Tatsache, dass ich keine Kontrolle über den Namen der anonymen Typen habe, und dass der RuntimeType für mich als Menschen nichtssagend ist - eine äußerst prekäre Situation. Nur Reflection und Hacks bringen mich da weiter, wenn ich auf die Member des anonymen Typen zugreifen möchte. Also z.B.: Es ist kein if(v.GetType() == typeof(<>f__AnonymousType2`2)) möglich, da ich einfach nicht weiß, was <>f__AnonymousType2`2 ist. Ich kann ja alles über Reflection ermitteln: Parameter-Name, Parameter-Typ, Parameter-Wert usw., aber eines nicht: Die genaue semantische Identität meines Typs (was bedeutet mir der Typ <>f__AnonymousType2`2 vgl. mit Type PersonProblem?). Bleibt noch der Weg über try>cast>catch, aber auch dafür muss ich wissen was zu was ich caste, und die Performance...
- Schwere Wartbarkeit: Wenn ich die Methode ändere, die das IEnumerable<object> zurückgibt, muss ich immer den Consumer mit anpassen. Ich muss zusehen, dass sowohl Parameter-Namen, als auch -Typ und -Reihenfolge weiterhin mit dem Code in der Methode synchron bleiben, die anonyme Typen zurückgibt. Das alles fängt leider kein Tool für mich ab, nicht der Compiler und nicht die statische Analyse.
Es gäbe noch weitere Probleme mit zurückgegebenen anonymen Typen, aber ich beschränke mich hier auf die für mich wichtigsten. Für mich sind anonyme Typen eben solange gut, wie ich sie nach dem Prinzip "set it, and forget it" verwenden kann. Sobald es an die Wiederverwendung von anonymen Typen jenseits von Methodengrenzen geht, beginnt für mich der "Vespennest".
> man kann zum Beispiel auch folgende Ansätze oder Erweiterungsmethoden benutzen [...]
Auch RefactorPro mit dem ich gerne arbeite hat das von Dir erwähnte Refactoring (Name Anonymous Type). Leider hilft es nicht, wenn ich im Consumer-Code aus IEnumerable<object> wieder ein Typ hydrieren möchte. Die Erweiterungsmethode aus dem codeproject-Artikel ist eine schöne Verpackung von Reflection-Code. In Deinem letzten Link fand ich dann das, woran auch ich fest glaube:
"You should consider to create theMyType
objects already when you get the data, instead of creating anonymously typed objects."Gruß
Marcel -
Am 15.12.2010 15:00, schrieb Frank Dzaebel [MVP]:
.. den ich ja anders sehe:
-> sie können sinnvoll/vorteilhaft auch in Methoden übergeben werden
und brauchen nicht nur innerhalb einer Methode benutzt werden.Einen anonymen Typ einer Methode zu übergeben, ist meistens eine
richtig schlechte Lösung, weil der Zugriff auf die Autoproperties
verkompliziert wird. Man braucht dann Latebinding
u/o Reflection, ohne dass es nötig wäre.
Stattdessen einen benannten Typ zu entwerfen und zu übergeben,
kostet fast nichts im Sinne von Arbeitszeit, weil anonyme Typen per
Definition POCOs sind und aus einem generierenden Statement im Stile:Select (o => new {o.Name, o.Age})
im Nu eine Definitionclass NameAndAge { string Name {get; set;} int Age {get; set;} }
gemacht ist
Dafür ein Vorteil zur Laufzeit und der Code ist sauberer.
Dass irgendwas irgendwie unter imaginierten Szenarien geht,
ist, obwohl formal zutreffend, kein Argument für Sinnhaftigkeit.Christoph
-
Hallo Christoph,
also da ist evtl. ein Missverständnis aufgekommen. Meine Meinung dazu nochmals zitiert: "
Als allgemeine Richtlinie empfehle ich immer, so typsicher wie möglich zu arbeiten
Im Prinzip sehe ich das also ähnlich wie ihr. Nur, dass es eben Fälle gibt, in denen anonyme Typen sinnvoll eingesetzt werden können und dies auch durch Übergabe an Methoden oder auch ausserhalb von Mthoden passiert.Chistoph schrieb:
> Man braucht dann Latebinding u/o Reflection, ohne dass es nötig wäre.
das ist nicht richtig. Ein Beispiel:private void Form1_Load(object sender, EventArgs e) { Methode(AnonymeListe()); } IEnumerable<object> AnonymeListe() { for (int i = 0; i < 10; i++) yield return new { Name = "Name" + i, Alter = 42 + i }; } private void Methode(IEnumerable<object> anonymeListe) { dataGridView1.DataSource = anonymeListe.ToList(); }
Im DataGridView wird - ohne Reflection zu implementieren - hüsch eine Liste von Name und Alter angezeigt.
> Stattdessen einen benannten Typ zu entwerfen und zu übergeben, kostet fast nichtsich stimme zu für viele Fälle, aber es gibt - wie ja bereits mehrfach erwähnt - ja Fälle, in denen das vorteilhaft nutzen kann (speziell dynamische interne Szenarien).
Übrigens erwähnte ich gerade den Resharper, damit kannst Du aus anonymen Typen automatisiert die POCOs erstellen! Microsoft selber benutzt anonyme Typen allerdings sehr stark etwa bei dem ASP.NET MVC Framework. Manchmal will man auch einfach durch eine Methode alle Fälle abdecken und dann führen anonyme Typen zu besserer Lesbarkeit, einfacherer Implementierung und manchmal auch besserer Performance/Speicherverbrauch - wie gesagt, nur manchmal und Vorsicht ist da natürlich angebracht, da hat Marcel auch schon ein paar mögliche Punkte aufgelistet.
Aber nochmal zur Erinnerung! Mit dem Wort "meistens" bei Dir stimme ich überein, anonyme Typen werden von der Häufigkeit eher selten gebraucht - nur sprechen wir hier über diese seltenen Fälle IMHO.
ciao Frank -
Hallo Marcel,
> [...] Identitätsverlust, Komplexe Differenziierung, Schwere Wartbarkeit ...im Prinzip sehe ich es ähnlich - wir sind nicht weit voneinander entfernt. Übrigens sehr angenehm, dass Du prägnant und mit Auslassungszeichen zitierst, so kann ich sehr gut verstehen, auf was es sich bezieht. Mein Ausdruck "weniger stark" ist auf Situationen gemünzt, in denen eben Vorteile durch die Verwendung anonymer Typen entstehen - dazu findet man auch viele Artikel und Aussagen - nicht nur unter .NET (s.a. Java). Allgemein sehe ich meine bescheidene Empfehlung: " [...] so typsicher wie möglich zu arbeiten" als Essenz. Also müssen es "begründete" Ausnahmen - genauso wie bei dynamic und object - bleiben, wodurch ich wieder ein wenig auf mein anfänglichen Hinweis zurückkomme. Wenn man so durch viele Artikel schaut, sieht man, dass ich mit meiner Bewertung zu den Einsatzszenarien und ihren "möglichen" Vorteilen nicht alleine stehe, C# MVPs wie etwa John Skeet etwa zeichnen ähnliche Möglichkeiten auf, obwohl sie auch die Beschränkungen (Limits) benennen. Das ist letztlich gründlich zu bewerten und technisch sicher auch zum Teil kontrovers.
ciao Frank -
Hallo Frank,
> im Prinzip sehe ich es ähnlich - wir sind nicht weit voneinander entfernt [...]. Allgemein sehe ich meine bescheidene Empfehlung: "[...] so typsicher wie möglich zu arbeiten." als Essenz.
Ich glaube, in diesem Punkt sind wir uns alle einig.
> C# MVPS wie John Skeet etwa zeichnen ähnliche Möglichkeiten auf, obwohl sie auch die Beschränkungen benennen.
Welche Artikel meinst Du konkret? Viele der neueren Artikel von John Skeet zu anonymen Typen kreisen semantisch um C# 5.0 und async-Methoden herum (die ich noch nicht wirklich kenne). So etwa: "The real world of anonymous types and dynamic", wo John den schönen Satz schreibt: "The extra local variables are back, because I don't like being dynamic for more type than I can help".Gruß
Marcel -
Hallo Marcel,
> Welche Artikel meinst Du konkret?
sorry, ich meinte Rick Strahl [MVP C#]. Zum Beispiel folgenden [Artikel von Rick Strahl] - zwar stimmen einige Aussagen nicht mehr für .NET 4.0 (der war ja noch für Vorversionen) aber dort zum Beispiel das JSON- Szenario, das auch wir haben, da wir u.a. Silverlight Domain Services dynamisch über WCF benutzen. So sagt er da klar:- Is it really all that useful - DEFINITELY
- I've also found Anonymous Types extremely useful for returning result values through serialization and as results for JSON based services.
ciao Frank - Is it really all that useful - DEFINITELY
-
Hallo Frank,
> Artikel von Rick Strahl, JSON-Szenario.
Das Beispiel ist gut, und es bestärkt mich in meinem Verständnis über die Schwierigkeiten, die mit der Weitergabe von anonymen Typen verbunden sind. Zunächst einmal ein kleiner Code, damit wir leichter über die Weitergabe von anonymen Typen reden können:using System; using System.Collections.Generic; using System.Web.Script.Serialization; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { // Anfrage kommt herein, wir erstellen als Antwort einen // anonymen Typ und geben es als Objekt zur Weiterverarbeitung frei. object anonymousType = MethodThatReturnsAnAnonymousTypeAsAnObject(); // XmlSerializer, BinaryFormatter & DataContractSerializer // koennen anonyme Typen nicht serialisieren, da sie u.a. nicht mit // [Serializable] markiert sind. DataContractJsonSerializer // kann es genausowenig weil anonyme Typen u.a. auch nicht mit // [DataContractAttribute] versehen sind. Also versuchen wir // wie wahrscheinlich Rick Strahl unser Glück und nehmen den JavaScriptSerializer serializer = new JavaScriptSerializer(); string jsonString = serializer.Serialize(anonymousType); // Ab diesem Zeitpunkt wird der anonyme Typ nicht mehr gebraucht! // Der JSON-String wird über den Draht geschickt. Console.WriteLine(jsonString); // Und kommt auf dem Client an. Wo wir das anonyme Objekt natürlich // nicht wiederherstellen koennen, da wir für Deserialize<T>(string) // einen Typ brauchen. Also begnügen wir uns mit einem Dictionary- // Objekt (in einem AJAX-Szenario würde jetz ein JavaScript-Objekt // instanziiert werden): Dictionary<string, object> deserializedAnonymousType = serializer.Deserialize<Dictionary<string, object>>(jsonString); // Wir koennen dennoch auf die Properties zugreifen, wenn auch nicht // in der gewohnten Form. foreach(KeyValuePair<string, object> kvp in deserializedAnonymousType) Console.WriteLine("Key: {0}, Value: {1}", kvp.Key, kvp.Value); Console.ReadKey(true); } static object MethodThatReturnsAnAnonymousTypeAsAnObject() { var anonymousType = new { Name = "Mustermann", Alter = 32 }; return anonymousType; } } }
Wie man aus dem obigen Code sehen kann, wird der anonyme Typ nachdem es die erstellende Methode verläßt nicht wieder weiterverwendet. Er wird einfach an JavaScriptSerializer.Serialize(object) übergeben und das war's. Requiescat in pace. Auf die Eigenschaften des anonymen Typs wird nicht weiter zugegriffen und dem JavaScriptSerializer könnte man genausogut einen stark typisierten Typ übergeben, er würde genausogut eine JSON-Zeichenfolge daraus erstellen. Die wirklichen Probleme kommen - in meinem Verständnis - erst auf dem Client, dort wo man aus der JSON-Zeichenfolge was konstruieren soll. Denn: Ein JavaScript-Objekt ist in einer AJAX-aktivierten Anwendung leicht erstellt, nicht so aber ein anonymes .NET-Objekt. Es gibt keine Metadaten, die eine Deserialisierung des JSON-Strings in ein anonymes Objekts ermöglichen könnten. Was sollen wir denn für ein T an JavaScriptSerializer<T>.Deserialize(string) übergeben? - Mit anderen Worten: Der anonyme Typ hat nicht wirklich seine erstellende Methode verlassen und wird nirgends wieder als Typ verwendet. Dies bestätigt das, was ich als "set it, and forget it"-Prinzip von anonymen Klassen benannt habe: Keine Wiederverwendung, keine Kopfschmerzen. Damit bin ich einverstanden.
Gruß
Marcel -
Hallo Marcel,
> [...] könnte man genausogut einen stark typisierten Typ übergeben ...Ich nehme mal als Grundlage ein Silverlight/WCF/JSON - Übergabe an WCF Data Services.
Ausgangs-Aufgabe sei einfach:
die Übergabe von "Daten" an einen Dienst oder der Empfang dieser Daten.
Dabei möchte man in diesem gedachten Szenario einerseits sehr flexibel Datenstrukturen und effizient übergeben und andererseits möglichst getypt arbeiten.
Nun ist ja gerade der Vorteil, dass man in Silverlight eben getypt (u.a. mit Linq und annonymen Typen) in C# arbeiten kann und trotzdem zum Beispiel quasi auf der Leitung ungetypt (also flexibel) Daten als JSON übergeben kann. Man möchte dann normal diese Daten über das Netz möglichst minimal (->Netzwerktraffic/Performance/Speicher) zum Empfänger senden.
Da fängt das Problem an. Es gibt im Standardfall nur die vorher definierten Typen, die auch über die Methoden des Domain Services angeboten werden. Bei grösseren Datenbanken ist es absolut illusorisch, alle Typen/Eigenschaften-Permutationen im Vorneherein anzubieten. Deswegen muss da in einigen Szenarien eine Zwischenlösung geschaffen werden, um solche Datenstrukturen zu halten oder "effizient" zu übersenden. Es geht eben dann nur über spät gebundene Methoden. Wenn man einen vorher definierten Typ aus einer C# Datei nehmen würde, würde wirklich (u.a.) zu viel über das Netz übertragen. Man will dann vielleicht nur 3 Eigenschaften, aber der Typ hat vielleicht 30. Das wäre hochgerechnet auf mehrere solche Aktionen einfach zu viel und spürbar und ein Vielfaches der Performance wäre verbraucht und das Netzwerk unnütz belastet. Auf der anderen Seite will man auch möglichst getypt arbeiten und Dein KeyValuePair wäre dann ganz sicher keine gewünschte Datenstruktur (für mich), sondern idealerweise der managed Typ, den ich auch im Client habe. An der Anzahl der Zeilen, die ich hier schreibe, sehe ich, dass es wohl auch nicht einfach zu verstehen ist, für mich ist es das, weil ich halt schon lange in diesem Szenario arbeite. Wenn ich und Rick das hier anscheinend nicht herüberbringen können, ist es wohl zu kompliziert, aber ich will hier auch keine Meinung "durchdrücken". Vielleicht belassen wir es einfach bei unseren Postings - es ist ja jetzt wirklich viel gepostet worden - und viele Argumente sind ja sicher auch verständlich geworden.
ciao Frank -
Hallo Frank,
> Man will dann vielleicht nur 3 Eigenschaften, aber der Typ hat vielleicht 30. Das wäre hochgerechnet auf mehrere solche Aktionen einfach zu viel [...] Auf der anderen Seite will man auch möglichst getypt arbeiten [... mit dem] managed Typ, den ich auch im Client habe.
Ich verstehe ja, warum man nur selektiv Daten übertragen möchte. Da hast Du Recht, keine Frage! Und auch dass dafür anonyme Typen sich gut anbieten, weil sie "on the fly" erstellt werden können.
Aber ich möchte *wirklich* verstehen, wie man auf dem Client aus einem JSON-String wieder genau den anonymen Typen auferstehen lassen kann, der in einer Assembly auf dem Server kompiliert wurde und sich wegen seiner Anonymität in keinem Datenvertrag befinden kann (man kann bei einem anonymen Typ weder Attribute setzen, noch Schnittstellen implementieren, noch hat er einen parameterlosen Konstruktor). Wie soll das also gehen?
s.a.: Passing an instance of anonymous type over WCF:
http://stackoverflow.com/questions/2307173/passing-an-instance-of-anonymous-type-over-wcfGruß
Marcel -
Hallo Marcel,
ich habe (und werde) mich etwas zurückgehalten, die weitere Diskussion aber mit Interesse verfolgt.
Aus einem JSON "Typ" kann man keinen anonymen Typ (Abschnitt Hinweise) erstellen,
ohne weitere Annahmen zu treffen. Dagegen stehen schon die Voraussetzungen.
So stellt JSON eine "ungeordnete Menge"dar, wohingegen ein anonymer Typ Reihenfolge
wie Typ berücksichtigt. Auch stellt es ein kleines Subset von Datentypen bereit, um nur zwei Punkte zu nennen.
Alles Dinge, die für eine Sprache wie JavaScript nicht (so) wichtig sind.Das die erwähnten RIA/WCF Data Services dies (neben anderen, siehe OData ) als Format nutzen können,
wird durch zusätzliche Metadaten, die am Server wie Client verfügbar sind, sind gewährleistet.Verzichtet man darauf, kann man zwar einen Typ erstellen, der gleiche Eigenschaften hat,
aber nur unter sehr vielen Annahmen und all den von Dir bereits genannten Risiken .Summa summarum (für mich):
Meine anfängliche Aussage ist eine Architektur-Empfehlung, nicht mehr und nicht weniger
und man kann ihr folgen oder andere Baustile bevorzugen. Mir geht es aber so:
Verzichtet man darauf, so kommt mir immer wieder Numerobis in den Sinn ;-)Gruß Elmar
-
Hallo Elmar,
Summa summarum (für mich): Meine anfängliche Aussage ist eine Architektur-Empfehlung, nicht mehr und nicht weniger [...]
Ich teile Deine Meinung voll und ganz.
Gruß
Marcel -
Hallo Marcel,
Elmar schrieb:
"RIA/WCF Data Services [...] wird durch zusätzliche Metadaten, die am Server
wie Client verfügbar sind, sind gewährleistet."
das ist in dynamischen RIA-Szenarien übrigens nicht der Fall - nur zur Erinnerung!
Das scheint für viele Leute sehr schwer zu sein, dies zu verstehen - sicher auch verständlich, da solche Notwendigkeiten erst in größeren Projekten auftreten und nicht jeder solche Projekte durchführt. Man kann RIA auch (gemischt) ohne Typen am Client betreiben - man wird dies zum Beispiel bei hohen Typ-Anzahlen tun (Performance-Aspekte, gerade, wenn diese eben wie bei Silverlight etwa gedownloaded werden müssen), oder bei permutativ gemischten Typ-Anforderungen am Client (also zum 3 Spalten aus Typ1, 2 Spalten aus Typ2 etwa).
In einfachen Szenarien kann man durchaus "alle" Typen clientseitig und serverseitig zur Verfügung haben - aber schon da wird man bzgl. best practices bereits klar von MS gewarnt (don't do this!). Aber gerade clientseitig sind eben häufig mehr notwendig. Hier bildet man sich gemischte Sichten, die ja auch gar nicht alle permutativ auf Servern gehalten werden könnten (noch sollten).
Bei all dem verzichtet man natürlich trotzdem nicht auf die typsicheren Zugriffe über die Services und nutzt diese, wenn "möglich", bzw. den Design/Anforderungs-Entscheidungen entsprechend abgewogen positiv zu entscheiden ist.
ciao Frank