Frage

Bedenken Sie:

var me = new { FirstName = "John", LastName = "Smith" };

Das ist in Ordnung, wie wir das dann tun können:

Console.WriteLine("{0} {1}", me.FirstName, me.LastName);

Wir können dies jedoch nicht:

public T GetMe()
{
    return new { FirstName = "John", LastName = "Smith" };
}

Weil wir die Art von T nicht kennen.

Wir könnten das tun:

public object GetMe()
{
    return new { FirstName = "John", LastName = "Smith" };
}

Aber dann müssten wir die Eigenschaften des Objekts mithilfe von Reflexion untersuchen, um darauf zuzugreifen:

var p = new Prog();
object o = p.GetMe();
Type t = o.GetType();
foreach (var prop in t.GetProperties())
{
    Console.WriteLine(prop.Name + ": " + prop.GetValue(o, null));
}

Was ist jedoch, wenn wir einen anonymen Typ nennen könnten, während wir ihn definieren? Natürlich wäre es nicht mehr anonym, aber es wäre prägnanter und wartbarer als eine normale Klassendefinition.

Bedenken Sie:

public Person GetMe()
{
    return new public class Person { FirstName = "John", LastName = "Smith" };
}

Der Vorteil ist, dass es dann möglich wäre, das Ergebnis einer komplizierten Linq -Abfrage aus einer Methode zurückzugeben, ohne die Klasse explizit definieren zu müssen.

Betrachten Sie diese relativ komplexe Linq -Abfrage:

List<int> list = new List<int>();
var query = from number in list
            select
                new
                    {
                        Number = number,
                        Square = number*number,
                        Absolute = Math.Abs(number),
                        Range = Enumerable.Range(0, number)
                    };

Anstatt eine Klasse wie SO zu definieren:

public class MyNumbers
{
    public int Number { get; set; }
    public int Square { get; set; }
    public int Absolute { get; set; }
    public IEnumerable<int> Range { get; set; }
}

Um die Abfragevariable aus einer Methode zurückzugeben, können wir stattdessen einfach Folgendes tun:

List<int> list = new List<int>();
return from number in list
            select new public class MyNumbers
                    {
                        Number = number,
                        Square = number*number,
                        Absolute = Math.Abs(number),
                        Range = Enumerable.Range(0, number)
                    };
War es hilfreich?

Lösung

Eigentlich gibt es einen "Hack", den Sie tun können, um einen anonymen Typ von einer Methode zurückzubekommen. Bedenken Sie:

public object MyMethod()
    {
        var myNewObject = new
        {
            stringProperty = "Hello, World!",
            intProperty = 1337,
            boolProperty = false
        };

        return myNewObject;
    }

    public T Cast<T>(object obj, T type)
    {
        return (T)obj;
    }

Sie können jetzt das tun:

var obj = MyMethod();
var myNewObj = Cast(obj, new { stringProperty = "", intProperty = 0, boolProperty = false });

Der MyNewobj wird jetzt ein Objekt des gleichen Typs wie der anonyme Typ sein.

Andere Tipps

Die Sprachfunktion, die Sie benötigen, ist:

public var GetMe()
{
    return new { FirstName = "John", LastName = "Smith" };
}

Das ist, var wäre als Methodenrückgabeart gültig, und der Compiler würde den tatsächlichen Typ aus dem, was zurückgegeben wird, schließen. Sie müssten dies dann auf der Anrufseite tun:

var me = GetMe();

Alle zwei anonymen Typen mit Mitgliedern desselben Typs wären derselbe Typ. Wenn Sie also andere Funktionen schreiben, die dasselbe Muster zurückgeben, hätten sie den gleichen Typ. Für alle Typen A und B, bei denen B eine Untergruppe der Mitglieder von A hat, ist A zuzuordnbar mit B (B ist wie eine Basisklasse von A). Wenn Sie geschrieben haben:

public var GetMeFrom(var names)
{
    return new { FirstName = names["First"], LastName = names["Last"] };
}

Der Compiler würde dies effektiv als generische Methode mit zwei Typparametern definieren. T1 die Art von Namen sein und T2 Der vom Indexer zurückgegebene Typ auf T1 Das akzeptiert eine Zeichenfolge. T1 würde eingeschränkt, damit es einen Indexer gibt, der eine Zeichenfolge akzeptiert. Und auf der Anrufseite würden Sie einfach alles übergeben, was einen Indexer hatte, der eine Zeichenfolge akzeptierte und zurückgegeben hat Jeder Typ, den Sie mögen, und das würde die Art von bestimmen FirstName und LastName in dem Typ zurückgegeben von GetMeFrom.

Typ -Inferenz würde also all dies für Sie herausfinden und automatisch die vom Code erfundenen Typeinschränkungen erfassen.

IMHO Das Wurzelproblem hat nichts mit anonymen Typen zu tun, sondern dass die Erklärung einer Klasse zu ausführlich ist.

Option 1:

Wenn Sie eine solche Klasse deklarieren könnten:

public class MyClass
{ properties={ int Number, int Square, int Absolute, IEnumerable<int> Range } }

Oder einen anderen ähnlich schnellen Weg (wie das Beispiel des Tuple), dann würden Sie nicht das Bedürfnis haben, mit anonymen Typen hacky Dinge zu tun, um einen Code zu speichern.

Wenn 'Compiler as a Service' in C#5 eintrifft, werden sie hoffentlich gute Arbeit leisten, um ihn zu integrieren, und wir werden in der Lage sein, diese Art von Problemen sauber zu lösen. Party wie es 1958 ist!

Option 2:

Alternativ können Sie in C#4 einfach einen anonymen Typ als umgeben dynamic und vermeiden Sie das ganze Casting. Dies öffnet sich natürlich den Laufzeitfehlern, wenn Sie eine Variable usw. umbenennen, usw.

Option 3:

Wenn C# Generika auf die gleiche Weise wie C ++ implementieren würde, können Sie den anonymen Typ in eine Methode übergeben, und solange er die richtigen Mitglieder hatte, würde er einfach kompilieren. Sie würden alle Vorteile der statischen Sicherheit und keiner der Nachteile erhalten. Jedes Mal muss ich tippen where T : ISomething In C# ärgere ich mich, dass sie das nicht getan haben!

Was Sie beschreiben (genannte anonyme Typen), sind grundsätzlich "Tupeltypen".

Ich denke, sie wären eine schöne Ergänzung zu C#.

Wenn ich eine solche Funktion für C#entwerfen würde, würde ich sie mit solcher Syntax freilegen:

tuple<int x, int y>

so dass Sie tun könnten:

public tuple<int x, int y> GetStuff()
{
}

Ich würde dann die Definition von anonymen Typen ändern, damit:

new { x = 2, y = 2}

hatte tuple<int x, int y> wie es Typ ist und nicht ein anonymer Typ.

Es ist etwas schwierig, dies mit der aktuellen CLR zu arbeiten, denn sobald Sie einen anonymen Typ in öffentlichen Unterschriften benennen können, müssen Sie in der Lage sein, sie über separat kompilierte Versammlungen zu vereinen. Es kann erreicht werden, indem ein "Modulkonstruktor" in jede Baugruppe eingebettet wird, die einen Tupel -Typ verwendet. Sehen dieser Beitrag zum Beispiel.

Der einzige Nachteil dieses Ansatzes ist, dass es das "faule" Modell der CLR für die Typengenerierung nicht respektiert. Das bedeutet, dass Baugruppen, die viele unterschiedliche Tupeltypen verwenden, etwas langsamere Lasttypen aufweisen. Ein besserer Ansatz wäre, die Tupel -Typen direkt zum CLR zu unterstützen.

Abgesehen von der Änderung des CLR denke ich, dass der Modulkonstruktor -Ansatz der beste Weg ist, um so etwas zu tun.

Ich würde dieses Feature lieben, es gab viele Male, dass ich das wollte.

Ein gutes Beispiel ist die Verarbeitung von XML. Sie analysieren sie zurück, um ein Objekt zurückzugewinnen, aber dann müssen Sie eine konkrete Version des Objekts erstellen, um sie an einen Anrufer zurücksenden zu können. Oft erhalten Sie XML, der sich sehr ändert und Sie viele Klassen erstellen müssen, um damit umzugehen. Wäre es nicht wunderbar, wenn Sie das Objekt einfach mit linqtoxml als var erstellen könnten, dann geben Sie das einfach zurück?

Ich denke, das wäre eine schöne Compiler -Magie für Tupel:

Erstellen eines Tupels:

(int, string, Person) tuple = (8, "hello", new Person());

gleichwertig:

Tuple<int,string,Person> tuple = new Tuple<int,string,Person>(8 ,"hello", new Person());

In einer Funktion:

public (int, string, Person) GetTuple(){
    return ...
}

Werte erhalten:

int number = tuple[1];
string text = tuple[2];
Person person = tuple[3];

Könnten Sie eine Schnittstelle zu den Eigenschaften FirstName und Lastname erstellen und diese verwenden?

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top