2016-03-31 14 views
1

Ich habe mit Typ Inferenz in C# gespielt und ich habe gelesen this thread. Wie im Thread angegeben, funktioniert Typ-Inferenz nicht für generische Delegaten (wenn Sie eine Methode an diesen Delegate-Parameter übergeben, ohne explizites Casting) wie Func, Action usw. Ich würde dann gerne LINQ-Operatoren wie SelectMany mit .net Func ausprobieren Klassen anstelle von Lambda-Ausdrücken, um das Ergebnis zu sehen. Es war jedoch nicht das Ergebnis, das ich erwartet hatte.Typ Inferenz für Delegat Parameter zu Methoden

Ich habe eine Testklasse namens L1 erstellt, die eine Liste von Strings enthält, um in SelectMany (flatten) zu verwenden. Zusätzlich habe ich eine Testmethode erstellt, um anstelle des Parameters Func type zu übergeben.

public class L1 
{ 
    private L1() {} 

    public L1(string m) 
    { 
     Isim = m; 
     numbers = new List<string> { "1", "2", "3", "4", "5" }; 
    } 

    public List<string> numbers; 
    public string Isim { get; private set; } 
} 
private static IEnumerable<int> a(L1 k) 
{ 
    return Enumerable.Empty<int>(); 
} 

Wenn ich wie die eine Erweiterungsmethode erstellt unten, können C# Compiler den Typ der generischen Parameter nicht Inferenz.

public static void Test<T1, T2>(this L1 l, Func<T1, IEnumerable<T2>> a) 
{ 
} 

(new L1("test")).Test(a); 

Es gibt 'Fehler CS0411: Der Typ Argumente für die Methode 'EnumSand.Test (L1, Func>)' kann nicht aus der Nutzung zu entnehmen. Versuchen Sie, die Typargumente explizit anzugeben. 'wie ich erwartet habe.

Wenn ich jedoch diese Methode eine in LINQ SelectMany Extension-Methode verwenden, gibt der Compiler keinen Fehler und es funktioniert.

L1[] l1 = new L1[5] { 
         new L1("one"), new L1("two"), 
         new L1("three"), new L1("four"), 
         new L1("five") 
        }; 

var slack = l1.SelectMany(a); 

foreach (var t in slack) 
{ 
    Console.WriteLine(t); 
} 

Also, was ist der Unterschied zwischen diesen Fällen und wie es in Select möglich ist, eine gute Typinferenz zu machen?

Antwort

2

Das Problem ist hier:

public static void Test<T1, T2>(this L1 l, Func<T1, IEnumerable<T2>> a) 

T2 int gebunden ist aber T1 alles sein kann, das ist, warum es nicht geschlossen werden kann.

Sie können entweder zweiten Parameter Func<L1, IEnmuerable<T2>> ändern und entfernen T1 ganz oder this L1 zu this T1 ändern.

EDIT: die Situation berücksichtigen, wenn Sie folgende Methoden:

private static IEnumerable<int> a(L1 k) 
{ 
    return Enumerable.Empty<int>(); 
} 

private static IEnumerable<int> a(string k) 
{ 
    return Enumerable.Empty<int>(); 
} 

Können Sie jetzt sagen, welche a Methode sollte für (new L1("test")).Test(a); Gebrauch verwendet werden?

+0

Meinst du compiler kann inder vom Rückgabetyp, aber nicht von Argumenten? 'Func > Selektor' in 'SelectMany' Unterschrift kennt bereits' TSource' aufgrund der Regeln der Erweiterungsmethode, und die Rückgabetyp-Inferenz ist in diesem Fall genug? – Deniz

+0

@Deniz, stimme ich dieser Antwort zu. Dies bedeutet nicht, dass der Compiler vom Rückgabetyp, nicht aber von Argumenten, schließen kann. Nicht sicher, warum du das denkst. –

+0

@AndrewSavinykh, habe ich versucht, T1 in L1, das gleiche Ergebnis zu ändern. – Deniz

Verwandte Themen