how to turn a string into a linq expression?

13,980

Solution 1

Here's an expression tree attempt. I still don't know if this would work with Entity framework, but I figure it is worth a try.

Func<T, int> MakeGetter<T>(string propertyName)
{
    ParameterExpression input = Expression.Parameter(typeof(T));

    var expr = Expression.Property(input, typeof(T).GetProperty(propertyName));

    return Expression.Lambda<Func<T, int>>(expr, input).Compile();  
}

Call it like this:

Build<T>(repo.getList(), MakeGetter<T>(classTypeId))

If you can use an Expression<Func<T,int>> in place of a just a Func, then just remove the call to Compile (and change the signature of MakeGetter).


Edit: In the comments, TravisJ asked how he could use it like this: w => "text" + w.classTypeId

There's several ways to do this, but for readability I would recommend introducing a local variable first, like this:

var getId = MakeGetter<T>(classTypeId);

return w => "text" + getId(w); 

The main point is that the getter is just a function, and you can use it exactly like you normally would. Read Func<T,int> like this: int DoSomething(T instance)

Solution 2

Here is an extension method for you with my testing code (linqPad):

class test
{
   public string sam { get; set; }
   public string notsam {get; set; }
}

void Main()
{
   var z = new test { sam = "sam", notsam = "alex" };

   z.Dump();

   z.GetPropertyByString("notsam").Dump();

   z.SetPropertyByString("sam","john");

   z.Dump();
}

static class Nice
{
  public static void  SetPropertyByString(this object x, string p,object value) 
  {
     x.GetType().GetProperty(p).SetValue(x,value,null);
  }

  public static object GetPropertyByString(this object x,string p)
  {
     return x.GetType().GetProperty(p).GetValue(x,null);
  }
}

results:

results

Solution 3

I haven't tried this, and not sure if it would work, but could you use something like:

b => b.GetType().GetProperty(classTypeId).GetValue(b, null);

Share:
13,980

Related videos on Youtube

Travis J
Author by

Travis J

I really appreciate the Stack Exchange community. This isn't a terrible search . VP of a medium company, B.S. in Computer Science, mostly working with the ASP.NET MVC technology stack. I am the only person at the company who deals with software development making me fill the rolls of a software designer, programmer, dba, server admin, and graphics artist. As you can see from my gravatar, this causes me to wear many hats (hint: they are all from an old winterbash). My main goals when designing and coding are: how can I make the user experience easiest, and how can I reduce redundancy. "Acknowledge your faults so you can overcome them."

Updated on September 15, 2022

Comments

  • Travis J
    Travis J over 1 year

    Similar: Convert a string to Linq.Expressions or use a string as Selector?

    A similar one of that one: Passing a Linq expression as a string?

    Another question with the same answer: How to create dynamic lambda based Linq expression from a string in C#?

    Reason for asking something which has so many similar questions:

    The accepted answer in those similar questions is unacceptable in that they all reference a library from 4 years ago (granted that it was written by code master Scott Gu) written for an old framework (.net 3.5) , and does not provide anything but a link as an answer.

    There is a way to do this in code without including a whole library.

    Here is some sample code for this situation:

        public static void getDynamic<T>(int startingId) where T : class
        {
            string classType = typeof(T).ToString();
            string classTypeId = classType + "Id";
            using (var repo = new Repository<T>())
            {
                Build<T>(
                 repo.getList(),
                 b => b.classTypeId //doesn't compile, this is the heart of the issue
                   //How can a string be used in this fashion to access a property in b?
                )
            }
        }
    
        public void Build<T>(
            List<T> items, 
            Func<T, int> value) where T : class
        {
            var Values = new List<Item>();
            Values = items.Select(f => new Item()
            {
                Id = value(f)
            }).ToList();
        }
    
        public class Item
        {
         public int Id { get; set; }
        }
    

    Note that this is not looking to turn an entire string into an expression such as

    query = "x => x.id == somevalue";
    

    But instead is trying to only use the string as the access

    query = x => x.STRING;
    
    • Hogan
      Hogan almost 12 years
      If you want to put a bounty on this question you should do so, saying such-and-such answer will be bountied is silly.
    • Travis J
      Travis J almost 12 years
      @Hogan - Sorry, I cannot post a bounty for another 2 days. If I could I would. Perhaps that is an issue you can raise on meta.
  • Travis J
    Travis J almost 12 years
    This looks interesting and at least compiles. Still have more testing to do.
  • Hogan
    Hogan almost 12 years
    I was able to get this to work in linqPad -- here is the code gist.github.com/3108507
  • Travis J
    Travis J almost 12 years
    @Paul - Thank you for some working code and example. I was also able to get this to work. I did not change the signature because it would have interfered with more linq down the line. I did have one question, what would I have to do to use MakeGetter in this way: w => "text" + MakeGetter<T>(classTypeId)? Similar to w => "text" + w.classTypeId.
  • Travis J
    Travis J almost 12 years
    This works in your example, however, I see no integration with linq here. See Paul's answer for a linq integration.
  • Hogan
    Hogan almost 12 years
    I guess, his works on a type mine works on an object... 6 of one. I think mine would be more performent since there is no templating needed.
  • Travis J
    Travis J almost 12 years
    @PaulPhillips - Thank you for the edit, and clarification. Although I have read a lot of documentation at MSDN and around the web I am still getting used to delegates, Funcs, and Expression trees. I appreciate it.