Returning values with a Func Delegate
Asked Answered
P

3

5

In an effort to learn more about Func Delegates and Expression trees, I put together a simple example, however I am not getting the results I expect. Below is my code that has a Func that expects a Params class and a List of Products. The idea is to apply the Params Class as a filter against a list of Products. As I said, this is just an exercise for me to learn how all this works.

I am expecting the delegate to return a least one Product object, however it returns null.

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"
       }
    };
}

classes:

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; }
}
Pulpiteer answered 21/12, 2013 at 15:30 Comment(2)
There is no problem with your filterFunc... but ToList() will return an instance of List<Product> and List<Product> is not the same type as Products so the as Products expression returns always null...Getup
Does List<Product> prods = filterFunc(param, products).ToList() is also null?Sight
D
7

The problem is that ToList returns a List<Product>, but that's a distinctly different type than Products. You could provide a constructor of Products which accepts an IEnumerable<Product> like this:

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

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

But if this is all your Products class does, it's probably a lot simpler to just get rid of it entirely and deal with IEnumerable<Product> (or List<Product>) wherever you need to handle a collection of Product objects:

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"
        },
    };
}
Dedicate answered 21/12, 2013 at 15:33 Comment(0)
G
2

Your call to .ToList() will return a List<Product>, not a Products (whatever that is), thus the call to as Products will fail its cast and will return null.

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

This might work (depending on the definition of Products which you haven't supplied:

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

Or possibly (if products has a constructor that accepts an IEnumerable):

Products prods = new Products(filterFunc(param, products));
Generation answered 21/12, 2013 at 15:38 Comment(0)
C
-1

In Func your are using Where method, that accepts IEnumerable<T> and condition, then returns IEnumerable<T>. It is wrapping input enumerable within another enumerable, that limits number of elements of underlying enumerable, so returned object implements IEnumerable but is not of type of input object (Products in your case).

Using as operator gives null if cast cannot be performed.

Cristiano answered 21/12, 2013 at 15:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.