Rahul
Rahul

Reputation: 77906

Use string variable in LINQ lambda expression

I have a class property name as string variable and want to use that in LINQ query. Below example:

public class Demo
{
  public string prop1 {get; set;} 
  public string prop2 {get; set;} 
  public string prop3 {get; set;} 
}

I can do this

var data = db.Single<Demo>(d => d.prop1 == "value");

But don't know what's the property is at runtime and getting that string parameter like

string propname = "prop2";

Is there any possibility to use that in lambda expression d => d.propname == "value"? I am not sure it can be and logically doesn't seem possible. so thought of posting a question and see if there is a way. Please suggest.

To Note, that Single() call is happening over MongoDB C# Driver and thus not sure whether reflection would work.

Upvotes: 2

Views: 2718

Answers (2)

sstan
sstan

Reputation: 36523

(This was the original provided before realizing that reflection wouldn't help in this particular case. See edit below for updated answer)

If you don't mind using reflection, you could do:

var data = db.Single<Demo>(d => "value" == (string)typeof(Demo).GetProperty(propname).GetValue(d));

EDIT

As others have hinted at in the comments, to make this work with MongoDB, you'll have to build the expression "by hand".

So, if I take the following statement:

var data = db.Single<Demo>(d => d.prop1 == "value");

I believe that the following should be equivalent, but building the lambda expression by hand:

string propname = "prop1"; // you can now change this to any valid property name.

var parameterExpresion = Expression.Parameter(typeof(Demo), "d");
var binaryExpression = Expression.Equal(
    Expression.Property(parameterExpresion, propname),
    Expression.Constant("value"));
var lambda = Expression.Lambda<Func<Demo, bool>>(binaryExpression, parameterExpresion);

var data = db.Single<Demo>(lambda);

... except that now, you should be able to change the value of propname to any valid property name, and it should just work.

Looking at how verbose the code gets when building lambdas manually really helps me appreciate all the compiler magic that happens without us ever noticing.

Upvotes: 5

squill25
squill25

Reputation: 1208

EDIT: this answer doesn't work for MongoDB. See @sstan's answer.

As @sstan said, you can use reflection:

var property = typeof(Demo).GetProperty("propertyName");
var data = db.Single<Demo>(d => (string)property.GetValue(d) == "value");

property is an object of type PropertyInfo which has a method GetValue. This method takes an object and returns that object's specified property.

Also, in @sstan's example, typeof(Demo).GetProperty("propertyName") will be called for each object which (depending on the size of your db) could be millions. It is better to get it once beforehand and reuse it.

Upvotes: 4

Related Questions