1

How to get single column with anonymous method using linq expression. Here's my code and it doesn't work:

public IEnumerable<object> GetPropertyValues<T>(string propName) where T : class
{
    return base.Query<T>().AsEnumerable()
        .Where(x => x.GetType().GetProperty(propName).Name == propName)
        .Select(x => x.GetType().GetProperty(propName).GetValue(x, null));
}

Here's the code in non generic method:

base.Query<Product>().Select(x => x.ProductName).AsEnumerable();

Thanks in advance.

derodevil
  • 811
  • 1
  • 11
  • 37
  • 4
    "it doesn't work" doesn't give us any useful information. What's the point of your `Where` clause? `GetProperty(propName)` will only ever return a property with that name... that's the whole point. – Jon Skeet Dec 14 '13 at 21:38
  • He's probably trying to do `base.Query().Pluck("ProductName").AsEnumerable();` – cwharris Dec 14 '13 at 21:42
  • I mean like `Select ProductName [Name] From Product` in SQL or `base.Query().Select(x => new { Name = x.ProductName }).AsEnumerable();` – derodevil Dec 14 '13 at 22:29

3 Answers3

4

This condition is incorrect, because when the property propName is missing, it crashes, rather than returning false:

.Where(x => x.GetType().GetProperty(propName).Name == propName)

If you wanted to say "the dynamic type has the property propName", a proper condition for it would look like this:

.Where(x => x.GetType().GetProperty(propName) != null)

Note that this is necessary only when some, but not all, subclasses of T have the desired property propName. If the property is present in the T itself, you could get property upfront, and do the rest of the query like this:

var theProp = typeof(T)..GetProperty(propName);
return base.Query<T>().AsEnumerable().Select(x => theProp.GetValue(x, null));
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
2

Once you call AsEnumerable() all further filtering will happen in memory rather than SQL. Thus, you could do:

var prop = typeof(T).GetProperty(propName);
return base.Query<T>().AsEnumerable().Select(t => prop.GetValue(t));

but this will select all columns of T into memory before filtering down to just one. To do the filtering in SQL, you'll need to dynamically construct an expression:

var prop = typeof(T).GetProperty(propName);
var parameter = Expression.Parameter(typeof(T));
var memberAccess = Expression.MakeMemberAccess(parameter, prop);
var selector = Expression.Lambda<Func<T, TProperty>>(memberAccess, parameter);
return base.Query<T>().Select(selector);
ChaseMedallion
  • 20,860
  • 17
  • 88
  • 152
  • I want to get all values based on specific property. I have tried your suggestion and I got error on "TProperty". Can you explain more? – derodevil Dec 14 '13 at 22:06
  • I change the TResult into object and it works. I have more question, can I put anonymous type like this? `base.Query().Selec(x => new { Name = x.ProductName });` – derodevil Dec 14 '13 at 22:24
1

For an enumeration of any type of objects...

public static IEnumerable<Object> Pluck<Object>(this IEnumerable<Object> source, string propName)
{
    return source
        .Select(x => new {
            obj: x
            prop: x.GetType().GetProperty(propName)
        })
        .Where(x => x.prop != null)
        .Select(x => x.prop.GetValue(x.obj));
};

For an enumeration of a single type of object...

public static IEnumerable<Object> Pluck<T>(this IEnumerable<T> source, string, propName)
{
    var prop = typeof(T).GetProperty(propName);
    return prop == null
         ? Enumerable.Empty<Object>()
         : source.Select(x => prop.GetValue(x));
};
cwharris
  • 17,835
  • 4
  • 44
  • 64