2013-03-29 14 views
6

Ich habe ein wenig über Typ Rückschluss gesucht, aber ich kann nicht scheinen, eine der Lösungen auf mein spezielles Problem anzuwenden.Typ Rückschluss auf verschachtelte generische Funktionen

Ich mache eine Menge Arbeit mit dem Bau und Weitergabe von Funktionen. Das scheint mir so zu sein, als müsste es den int-Typ ableiten können. Das einzige, was mir einfällt, ist, dass der Lambda-Rückgabetyp nicht vom Typ-Inferenzalgorithmus überprüft wird. Ich habe unnötige Logik entfernt, um das Problem klarer zu zeigen.

Func<T> Test<T>(Func<Func<T>> func) 
{ 
    return func(); 
} 

diese kompiliert:

Func<int> x = Test<int>(() => 
    { 
     int i = 0; 
     return() => i; 
    }); 

aber das gibt die Fehlermeldung „Die Typargumente für die Methode kann nicht von der Verwendung abgeleitet werden versuchen, die Art Argumente Angabe ausdrücklich.“:

Func<int> x = Test(() => 
    { 
     int i = 0; 
     return() => i; 
    }); 

Ich denke, ich möchte einfach nur wissen, warum das so funktioniert und wie es weiter geht.

+0

sehr ähnliche Frage, aber nicht ganz das gleiche http://StackOverflow.com/Questions/6090159/Inferring-Generic-Types-With-Functional-Composition –

Antwort

7

Ich würde sagen, dass die richtige Antwort auf die Frage nach E.Lippert in SO Why can't an anonymous method be assigned to var?

gegeben Aber lassen Sie uns mit Ihrem Beispiel ein wenig spielen:

Func<Func<int>> f =() => 
{ 
    int i = 0; 
    return() => i; 
}; 

Func<int> x = Test(f); //it compiles OK 

Kein Problem in Typinferenz mit Ihrem Func<T> Test<T>(Func<Func<T>> func) hier. Das Problem ist darin verborgen, dass Sie einen anonymen Lambda-Ausdruck verwenden, dessen Typ nicht abgeleitet werden kann. Versuchen Sie folgendes:

var f =() => 
{ 
    int i = 0; 
    return() => i; 
}; 

Es Compiler Error CS0815 gibt, sagen

Kann Lambda-Ausdruck auf eine implizit typisierte lokale Variable

und die Erklärung ist nicht abtreten:

Ein Ausdruck, der als Initialisierer für eine implizit typisierteverwendet wird 210 Variable muss einen Typ haben. Da anonyme Funktionsausdrücke, Methodengruppenausdrücke und der Null-Literalausdruck keinen Typ aufweisen, sind sie keine geeigneten Initialisierer. Eine implizit typisierte Variable kann nicht mit einem Nullwert in ihrer Deklaration initialisiert werden, obwohl ihr später der Wert null zugewiesen werden kann.

Kommen wir nun noch etwas anderes versuchen:

var x = Test(() => 
{ 
    Func<int> f =() => 0; 
    return f; 
}); 

es auch kompiliert.Also das Problem mit Ihrem ursprünglichen Beispiel war eigentlich mit dieser Zeile:

return() => i; 

Wir können weiter gehen und nach dem, was Eric Lippert sagt in seiner Antwort bieten eine weitere Funktion, dies zu wickeln:

static Func<T> GetFunc<T>(Func<T> f) { return f; } 

wir jetzt kann Ihren Code wie schreiben:

var x = Test(() => 
{ 
    int i = 0; 
    return GetFunc(() => i); 
}); 

Und es funktioniert auch.

Soweit ich verstehe, ist dies alles ein Overhead und Sie sollten nur einen expliziten Typ angeben. Während diese Problemumgehungen geeignet sind, wenn Sie ein Lambda benötigen, geben Sie ein Objekt des anonymen Typs zurück.

Verwandte Themen