TheBoubou
TheBoubou

Reputation: 19903

Use variable value as field with LINQ

I have this object :

public class MyObject
{
    public int Id { get; set; }
    public string FieldA { get; set; }
    public string FieldB { get; set; }
    public string FieldC { get; set; }
    public string FieldD { get; set; }
}

I have an IList<> of this object :

IList<MyObject> MyListObject = new List<MyObject>();

I do a Linq query on it :

var result = (from p in MyListObject where p.FieldC == "Test" select p.FieldA);

In this case, I return "p.FieldA" but sometimes I need to return "p.FieldB". I'd like put the name of the field (FieldA or FieldB) in a variable like this

var myvar = "FieldB"
var result = (from p in MyListObject where p.FieldC == "Test" select p.????);

How use myvar content (FieldB) as field name in the Linq query ?

Thanks,

Upvotes: 1

Views: 8242

Answers (4)

roomaroo
roomaroo

Reputation: 5871

You can use reflection to get the value of a property based on its name. This will allow you to select any property from you class.

Here's an example using an extension method on the MyObject class:

    public static string GetPropertyValue(this MyObject myObj, string propertyName)
    {
        var propInfo = typeof(MyObject).GetProperty(propertyName);

        if (propInfo != null)
        {
            return propInfo.GetValue(myObj, null).ToString();
        }
        else
        {
            return string.Empty;
        }
    }

Your LINQ query would then look like this:

string propName = "FieldB";
var result = from m in myList where m.FieldC == "Test" select m.GetPropertyValue(propName);

Upvotes: 0

kͩeͣmͮpͥ ͩ
kͩeͣmͮpͥ ͩ

Reputation: 7846

If you want it to work with IQueryable, you could do something like this:

var filtered = MyListObject.Where(p => p.FieldA == "Test");

var results = condition ? filtered.Select(p => p.FieldA) : filtered.Select(p => p.FieldB);

which can be refactored to:

Expression<Func<MyObject,string>> selector;

switch(condition)
{
    case "FieldA": selector = o => o.FieldA; break;
    case "FieldB": selector = o => o.FieldB; break;
    // other cases here
    default: throw new NotImplmentedException();
}

var results = MyListObject.Where(p => p.FieldA == "Test").Select(selector);

Upvotes: 0

GvS
GvS

Reputation: 52518

If your method itself knows it has to choose between FieldA and FieldB you can use:

var whatField = "FieldA";
var result = (from p in MyListObject 
     where p.FieldA == "Test" 
     select (whatField == FieldA ? p.FieldA : p.FieldB));

If you have more as 2 options, I would choose to pass a lambda;

Func<MyObject, object> fieldGetter;

// Option A, switch
switch (whatField) {
   case "FieldA": fieldGetter = o => o.FieldA; break;
   case "FieldB": fieldGetter = o => o.FieldB; break;
   // More options
}

// Option B using reflection:
var t = typeof(MyObject);
var prop = t.GetProperty(whatField);
fieldGetter = o => prop.GetValue(o, null);

// Linq then looks like
var result = (from p in MyListObject 
     where p.FieldA == "Test" 
     select fieldGetter(p));

The advantage of using the lambda is, you can split your logic, what field and how to query. And you can even make it work for different types:

IEnumerable<T> Query<T>(IQueryable<MyObject> MyListObject, Func<MyObject, T> fieldGetter) {
  return result = (from p in MyListObject 
       where p.FieldA == "Test" 
       select fieldGetter(p));
}

// call using:

var result = Query(MyListObject, o => o.FieldA);

Upvotes: 5

Rafal Spacjer
Rafal Spacjer

Reputation: 4918

Is FieldA and FieldB the same type?

If yes then you can do something like this:

var result = (from p in MyListObject where p.FieldA == "Test" 
             select (condition ? p.FieldA : p.FieldB));

Upvotes: 0

Related Questions