Given that I have an IEnumerable<T>
, where T
is any object, how can I select a specific property from it, given that I know the name of the one of the property names at run time as a string?
For example:
var externalIEnumerable = DataPassedFromConsumingCode(); // `IEnumerable<T>`
string knownPropertyName = "Foo";
var fooSelect = externalIEnumerable.Select(...);
In essence, I'm obviously just doing externalIEnumerable.Select(x=> x.Foo);
, but I need to perform this Select
at runtime, when I don't have control over when it's initially created.
--
ANSWER: Based on AlanT's answer, here's what I actually did:
public Expression<Func<TItem, object>> SelectExpression<TItem>(string fieldName)
{
var param = Expression.Parameter(typeof(TItem), "item");
var field = Expression.Property(param, fieldName);
return Expression.Lambda<Func<TItem, object>>(field,
new ParameterExpression[] { param });
}
I kept it as an Expression, because calling Compile
caused the IQueryable to be Enumerated, which meant the database was hit unnecessarily. So, to use it, I just do the following:
string primaryKey = _map.GetPrimaryKeys(typeof(TOriginator)).Single();
var primaryKeyExpression = SelectExpression<TOriginator>(primaryKey);
var primaryKeyResults = query.Select(primaryKeyExpression).ToList();
You can create custom dynamic objects by using the classes in the System. Dynamic namespace. For example, you can create an ExpandoObject and specify the members of that object at run time. You can also create your own type that inherits the DynamicObject class.
In C# 4.0, a new type is introduced that is known as a dynamic type. It is used to avoid the compile-time type checking. The compiler does not check the type of the dynamic type variable at compile time, instead of this, the compiler gets the type at the run time.
Use the IEnumberable interface in C#The IEnumerable interface is yet another interface used often to represent read-only collections of data. If you simply want to enumerate the elements of a collection, you can use IEnumerable as shown below.
It is possible to do this using an Expression
e.g.
private class Foo {
public string Bar { get; set; }
}
private IEnumerable<Foo> SomeFoos = new List<Foo>() {
new Foo{Bar = "Jan"},
new Foo{Bar = "Feb"},
new Foo{Bar = "Mar"},
new Foo{Bar = "Apr"},
};
[TestMethod]
public void GetDynamicProperty() {
var expr = SelectExpression<Foo, string>("Bar");
var propValues = SomeFoos.Select(expr);
Assert.IsTrue(new[] { "Jan", "Feb", "Mar", "Apr" }.SequenceEqual(propValues));
}
public static Func<TItem, TField> SelectExpression<TItem, TField>(string fieldName) {
var param = Expression.Parameter(typeof(TItem), "item");
var field = Expression.Property(param, fieldName);
return Expression.Lambda<Func<TItem, TField>>(field, new ParameterExpression[] { param }).Compile();
}
hth,
Alan.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With