2012-05-09 16 views
6

den Code unten kehrt gilt:eine Funktion Delegat zuweisen, die einen anonymen Typ einer Variablen

IEnumerable<SomeThing> things = ...; 

// map type SomeThing to a new anonymous type, resulting in a strongly typed 
// sequence based on an anon type 

var newList = things.Select(item => 
    { 
     return new 
     { 
      ID = item.ID, 
      DateUpdatedOrCreated = ((DateTime)(item.DateUpdated ?? 
        item.DateCreated)).ToShortDateString(), 
      Total = item.Part1 + item.Part2 
     }; 
    }); 

newList erscheint jetzt in Visual Studio als IEnumerable<'a> und ist stark mit dem anonymen Typ in der Funktion erstellt eingegeben haben. Das ist so cool.

Was ich kann nicht scheinen zu tun ist, einen Weg nur die Lambda-Ausdruck zuweisen herauszufinden (und nicht die Aufzählung) eine implizit typisierte Variablen. Auch wenn der Compiler kein Problem mit dem anonymen Typ im Zusammenhang mit oben hat, wenn ich versuche, (sagen wir)

var func = (SomeThing item)=> { 
     return new { ... }; 
    }; 

erhalte ich die Fehlermeldung „Kann nicht Lambda-Ausdruck zuweisen implizit typisierte lokale Variable“. Dies scheint eine seltsame Compiler-Beschränkung zu sein; Wenn ich etwas nicht vermisse, sind die Typen im zweiten Beispiel genauso eindeutig wie im ersten Beispiel: Beide Typparameter sind gut definiert.

Gibt es eine Möglichkeit, dies zu tun? Da es sich um einen anonymen Typ handelt, kann ich natürlich keinen Typ verwenden, um ihn explizit zuzuweisen. Daher scheint es, als würde ich eine Klasse für den Ausgabetyp erstellen, wenn nicht.

aktualisieren

Kurz nachdem mit Jon Skeet Antwort, fand ich ein ähnliches Dilemma instanziieren Klassen über meine fröhliche Art und Weise gehen. Falls es nicht offensichtlich ist, kann derselbe Trick verwendet werden, um stark typisierte Klassen unter Verwendung von abgeleiteten anonymen Typen zu erzeugen.

class Processor<T,U> 
{ 
    public Processor(Func<T,U> func) { 

    } 
} 

// func is a delegate with anon return type created using method in answer below 

var instance = new Processor(func); // does not compile! Requires type arguments! 

können nicht direkt erstellt werden, sondern kann in der gleichen Weise, wie der Trick unten erstellt werden: es

public static Processor<T,U> Create<T,U>(Func<T,U> func) { 
    return new Processor<T,U>(func); 
} 

var instance = Processor.Create(func); // all good 

Antwort

8

Sie können tun, über Typinferenz:

var func = BuildFunc((SomeThing item) => { 
    return new { ... }; 
}); 

... 

static Func<TSource, TResult> BuildFunc<TSource, TResult>(
    Func<TSource, TResult> function) { 
    return function; 
} 

Beachten Sie, dass BuildFunc tut nichts wirklich - es stellt nur den Methodenaufruf zur Verfügung, der benötigt wird, um den Compiler dazu zu bringen, Inferenz für die generischen Typargumente für Func<,> zu tun - er fügt die Information tha hinzu Sie interessiert sich für Func<,>, im Grunde - das sind Informationen, die nicht als Teil einer Variablendeklaration angegeben werden können, ohne auch die Typargumente anzugeben.

+0

Dies funktioniert, weil Typ Rückschluss für Generics klüger ist als Typ Inferenz für 'var'. (Ich nehme an, dass Jon in der Lage sein könnte zu erklären, warum, obwohl ich nicht kann.) – Servy

+0

Gute Antwort. Zusatzinfo: Dies funktioniert, weil Sie hier den Typ der Variablen nicht angeben müssen. Der Compiler kann nicht nur den Typ für die Variable ableiten, da mehrere Delegattypen zur Auswahl stehen. – usr

+0

@Servy: Es ist nicht wirklich eine Frage der Klugheit als solche - es ist eine Frage der Lage zu spezifizieren, dass Sie einen 'Func' Delegaten wollen, aber das generisch spezifizieren. –

Verwandte Themen