2013-12-21 10 views
5

In dem Bemühen, mehr über Func Delegates und Expression Bäume zu lernen, habe ich ein einfaches Beispiel zusammengestellt, aber ich bekomme nicht die Ergebnisse, die ich erwarte. Unten ist mein Code, der eine Func hat, die eine Params-Klasse und eine Liste der Produkte erwartet. Die Idee ist, die Params-Klasse als Filter für eine Liste von Produkten zu verwenden. Wie gesagt, dies ist nur eine Übung für mich zu lernen, wie das alles funktioniert.Rückgabe von Werten mit einem Func Delegaten

Ich erwarte, dass der Delegat mindestens ein Product-Objekt zurückgibt, jedoch gibt es null zurück.

static void Main(string[] args) 
{ 
    Products products = CreateProducts(); 

    Params param = new Params { Val = "ABC"}; 

    Func<Params, Products, IEnumerable<Product>> filterFunc = 
     (p, r) => r.Where(x => x.Sku == p.Val).AsEnumerable(); 

    Products prods = filterFunc(param, products).ToList() as Products;// returns null 
} 


private static Products CreateProducts() 
{ 
    return new Products 
    { 
     new Product{ 
      Price = 25.00, 
      Sku = "ABC" 
     }, 
     new Product{ 
      Price = 134.00, 
      Sku = "DEF" 
     } 
    }; 
} 

Klassen:

public class Params 
{ 
    public String Val { get; set; } 
} 

public class Products : List<Product> 
{ 
} 

public class Product 
{ 
    public String Sku { get; set; } 
    public double Price { get; set; } 
} 
+1

Es gibt kein Problem mit Ihrem 'filterFunc' ... aber' ToList() 'gibt eine Instanz von' List 'zurück und' List 'ist nicht der gleiche Typ wie' Products' also gibt der 'as Products' Ausdruck immer' null' zurück ... – nemesv

+0

Ist 'List prods = filterFunc (param, products) .ToList()' ist auch null? –

Antwort

7

Das Problem ist, dass ToList ein List<Product> gibt, aber das ist eine deutlich andere Art als Products. Sie könnten einen Konstruktor von Products schaffen, die eine IEnumerable<Product> wie dies akzeptiert:

public class Products : List<Product> { 
    public Products(IEnumerable<Product> products) : base(products) { 
    } 
} 

Products prods = new Products(filterFunc(param, products)); 

Aber wenn dies alle Ihre Products Klasse tut, ist es wahrscheinlich viel einfacher, nur loswerden vollständig und befassen sich mit IEnumerable<Product> (oder List<Product>), wo Sie eine Sammlung von Product Objekte behandeln müssen:

IEnumerable<Product> products = CreateProducts(); 
Params param = new Params { Val = "ABC"}; 
Func<Params, IEnumerable<Product>, IEnumerable<Product>> filterFunc = 
    (p, r) => r.Where(x => x.Sku == p.Val); 
IEnumerable<Product> prods = filterFunc(param, products); 

private static IEnumerable<Product> CreateProducts() 
{ 
    return new Products[] { 
     new Product{ 
      Price = 25.00, 
      Sku = "ABC" 
     }, 
     new Product{ 
      Price = 134.00, 
      Sku = "DEF" 
     }, 
    }; 
} 
-1

In Func Ihre verwenden Wo Methode, die IEnumerable<T> und Bedingung akzeptiert, dann kehrt IEnumerable<T>. Es ist Wrapping-Eingang, der innerhalb eines anderen Aufzählungselements aufzählbar ist und die Anzahl der Elemente des zugrunde liegenden Aufzählungselements begrenzt, sodass das zurückgegebene Objekt IEnumerable implementiert, aber nicht vom Typ des Eingabeobjekts ist (Produkte in Ihrem Fall).

Mit as Operator gibt Null, wenn Cast nicht ausgeführt werden kann.

2

Ihr Anruf zu .ToList() kehrt ein List<Product>, keine Products (was immer das ist), so dass der Anruf an as Products seinen Guss scheitern und null zurück.

Products prods = filterFunc(param, products).ToList() as Products;// returns null 

Dies könnte funktionieren (abhängig von der Definition von Products, die Sie nicht geliefert haben:

List<Product> prods = filterFunc(param, products).ToList(); 

Oder vielleicht (wenn Produkte einen Konstruktor hat, die eine IEnumerable akzeptiert):

Products prods = new Products(filterFunc(param, products));