1

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,

TheBoubou
  • 19,487
  • 54
  • 148
  • 236

4 Answers4

5

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);
GvS
  • 52,015
  • 16
  • 101
  • 139
  • This will not work because your fieldGetter is Func, this will work only if your fieldGetter is of type Expression>, you will get an error that Invoke not supported while running it. And you will have to combine to linq expressions. – Akash Kava Mar 30 '11 at 08:23
  • Option 2 is a good answer as it allows you to add more field selection by adding more entries to the switch. – SecretDeveloper Mar 30 '11 at 08:27
  • @Akash Kava, for LINQ to Objects it would work. The reflection does not work on the DB server anyway, so I think it is safer to not use the Expression syntax. Correct me if I'm wrong. – GvS Mar 30 '11 at 08:32
  • Yes you are right, my bad, I thought he will be querying against DB. – Akash Kava Mar 30 '11 at 08:38
0

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));
Rafal Spacjer
  • 4,838
  • 2
  • 26
  • 34
  • Same type yes. Your solution is ok, for 2 field but I can have 3 field in my class. I'd like an another solution than a switch – TheBoubou Mar 30 '11 at 08:11
  • But how would you like to choose appropriate field? There has to be some logic. You can of course use a method in select, but still in this method there will be if or switch (or any other solution to choose good field) – Rafal Spacjer Mar 30 '11 at 08:26
0

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);
roomaroo
  • 5,831
  • 4
  • 31
  • 31
0

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);
kͩeͣmͮpͥ ͩ
  • 7,783
  • 26
  • 40