Reflection to call generic method with lambda expression parameter - c#

I'm looking for a way to call a generic method with a lambda expression that calls Contains in an array of items.
In this case I'm using Entity Framework Where method, but the scenario could be applied in other IEnumerables.
I need to call the last line of the above code through Reflection, so I can use any type and any property to pass to the Contains method.
var context = new TestEntities();
var items = new[] {100, 200, 400, 777}; //IN list (will be tested through Contains)
var type = typeof(MyType);
context.Set(type).Where(e => items.Contains(e.Id)); //**What is equivalent to this line using Reflection?**
In research, I've noticed that I should use GetMethod, MakeGenericType and Expression to achieve that, but I couldn't figure out how to do it. It would be very helpful to have this sample so I can understand how Reflection works with Lambda and Generic concepts.
Basically the objective is to write a correct version of a function like this:
//Return all items from a IEnumerable(target) that has at least one matching Property(propertyName)
//with its value contained in a IEnumerable(possibleValues)
static IEnumerable GetFilteredList(IEnumerable target, string propertyName, IEnumerable searchValues)
{
return target.Where(t => searchValues.Contains(t.propertyName));
//Known the following:
//1) This function intentionally can't be compiled
//2) Where function can't be called directly from an untyped IEnumerable
//3) t is not actually recognized as a Type, so I can't access its property
//4) The property "propertyName" in t should be accessed via Linq.Expressions or Reflection
//5) Contains function can't be called directly from an untyped IEnumerable
}
//Testing environment
static void Main()
{
var listOfPerson = new List<Person> { new Person {Id = 3}, new Person {Id = 1}, new Person {Id = 5} };
var searchIds = new int[] { 1, 2, 3, 4 };
//Requirement: The function must not be generic like GetFilteredList<Person> or have the target parameter IEnumerable<Person>
//because the I need to pass different IEnumerable types, not known in compile-time
var searchResult = GetFilteredList(listOfPerson, "Id", searchIds);
foreach (var person in searchResult)
Console.Write(" Found {0}", ((Person) person).Id);
//Should output Found 3 Found 1
}
I'm not sure if the other questions address this scenario, because I don't think I could clearly understand how Expressions work.
Update:
I can't use Generics because I only have the type and the property to be tested (in Contains) at run-time. In the first code sample, suppose "MyType" is not known at compile time. In the second code sample, the type could be passed as a parameter to the GetFilteredList function or could be get via Reflection (GetGenericArguments).
Thanks,

After a wide research and a lot of study of Expressions I could write a solution myself. It certainly can be improved, but exactly fits my requirements. Hopefully it can help someone else.
//Return all items from a IEnumerable(target) that has at least one matching Property(propertyName)
//with its value contained in a IEnumerable(possibleValues)
static IEnumerable GetFilteredList(IEnumerable target, string propertyName, IEnumerable searchValues)
{
//Get target's T
var targetType = target.GetType().GetGenericArguments().FirstOrDefault();
if (targetType == null)
throw new ArgumentException("Should be IEnumerable<T>", "target");
//Get searchValues's T
var searchValuesType = searchValues.GetType().GetGenericArguments().FirstOrDefault();
if (searchValuesType == null)
throw new ArgumentException("Should be IEnumerable<T>", "searchValues");
//Create a p parameter with the type T of the items in the -> target IEnumerable<T>
var containsLambdaParameter = Expression.Parameter(targetType, "p");
//Create a property accessor using the property name -> p.#propertyName#
var property = Expression.Property(containsLambdaParameter, targetType, propertyName);
//Create a constant with the -> IEnumerable<T> searchValues
var searchValuesAsConstant = Expression.Constant(searchValues, searchValues.GetType());
//Create a method call -> searchValues.Contains(p.Id)
var containsBody = Expression.Call(typeof(Enumerable), "Contains", new[] { searchValuesType }, searchValuesAsConstant, property);
//Create a lambda expression with the parameter p -> p => searchValues.Contains(p.Id)
var containsLambda = Expression.Lambda(containsBody, containsLambdaParameter);
//Create a constant with the -> IEnumerable<T> target
var targetAsConstant = Expression.Constant(target, target.GetType());
//Where(p => searchValues.Contains(p.Id))
var whereBody = Expression.Call(typeof(Enumerable), "Where", new[] { targetType }, targetAsConstant, containsLambda);
//target.Where(p => searchValues.Contains(p.Id))
var whereLambda = Expression.Lambda<Func<IEnumerable>>(whereBody).Compile();
return whereLambda.Invoke();
}

In order to avoid using generics (since the types are not known at design time) you could use some reflection and build the expression "by hand"
You would need to do this by defining a "Contains" expression inside one Where clause:
public IQueryable GetItemsFromContainsClause(Type type, IEnumerable<string> items)
{
IUnitOfWork session = new SandstoneDbContext();
var method = this.GetType().GetMethod("ContainsExpression");
method = method.MakeGenericMethod(new[] { type });
var lambda = method.Invoke(null, new object[] { "Codigo", items });
var dbset = (session as DbContext).Set(type);
var originalExpression = dbset.AsQueryable().Expression;
var parameter = Expression.Parameter(type, "");
var callWhere = Expression.Call(typeof(Queryable), "Where", new[] { type }, originalExpression, (Expression)lambda);
return dbset.AsQueryable().Provider.CreateQuery(callWhere);
}
public static Expression<Func<T, bool>> ContainsExpression<T>(string propertyName, IEnumerable<string> values)
{
var parameterExp = Expression.Parameter(typeof(T), "");
var propertyExp = Expression.Property(parameterExp, propertyName);
var someValue = Expression.Constant(values, typeof(IEnumerable<string>));
var containsMethodExp = Expression.Call(typeof(Enumerable), "Contains", new[] { typeof(string) }, someValue, propertyExp);
return Expression.Lambda<Func<T, bool>>(containsMethodExp, parameterExp);
}
In this case "Codigo" is hard-coded, but it could be a parameter to get any property of the type you define.
You could test it by using:
public void LambdaConversionBasicWithEmissor()
{
var cust= new Customer();
var items = new List<string>() { "PETR", "VALE" };
var type = cust.GetType();
// Here you have your results from the database
var result = GetItemsFromContainsClause(type, items);
}

You can solve your problem by using the following set of classes.
First, we need to create a Contains class which will decide which items will be chosen from the source array.
class Contains
{
public bool Value { get; set; }
public Contains(object[] items, object item)
{
Value = (bool)(typeof(Enumerable).GetMethods()
.Where(x => x.Name.Contains("Contains"))
.First()
.MakeGenericMethod(typeof(object))
.Invoke(items, new object[] { items, item }));
}
}
Then we need to create a Where class which will be used to form a predicate based on which items will be selected. It should be clear that in our case, we are going to use the Contains class for our predicate method.
class Where
{
public object Value { get; set; }
public Where(object[] items, object[] items2)
{
Value = typeof(Enumerable).GetMethods()
.Where(x => x.Name.Contains("Where"))
.First()
.MakeGenericMethod(typeof(object))
.Invoke(items2, new object[] { items2, new Func<object, bool>(i => new Contains(items, i).Value) });
}
}
The last step is simply to invoke the result we got from the Where class, which is actually of type Enumerable.WhereArrayIterator and not of type List, since the result of the Where Extension method is a product of deferred execution.
Thus we need to create a non deferred object, by calling its ToList Extension Method, and get our result.
class ToList
{
public List<object> Value { get; set; }
public ToList(object[] items, object[] items2)
{
var where = new Where(items, items2).Value;
Value = (typeof(Enumerable).GetMethods()
.Where(x => x.Name.Contains("ToList"))
.First()
.MakeGenericMethod(typeof(object))
.Invoke(where, new object[] { where })) as List<object>;
}
}
In the end, you can simply test the whole process out by using the following class.
class Program
{
static void Main()
{
var items = new object[] { 1, 2, 3, 4 };
var items2 = new object[] { 2, 3, 4, 5 };
new ToList(items, items2).Value.ForEach(x => Console.WriteLine(x));
Console.Read();
}
}

Related

Detect if an object is a ValueTuple

I have a use case where I need to check if a value is a C# 7 ValueTuple, and if so, loop through each of the items. I tried checking with obj is ValueTuple and obj is (object, object) but both of those return false. I found that I could use obj.GetType().Name and check if it starts with "ValueTuple" but that seems lame to me. Any alternatives would be welcomed.
I also have the issue of getting each item. I attempted to get Item1 with the solution found here: How do I check if a property exists on a dynamic anonymous type in c#? but ((dynamic)obj).GetType().GetProperty("Item1") returns null. My hope was that I could then do a while to get each item. But this does not work. How can I get each item?
Update - more code
if (item is ValueTuple) //this does not work, but I can do a GetType and check the name
{
object tupleValue;
int nth = 1;
while ((tupleValue = ((dynamic)item).GetType().GetProperty($"Item{nth}")) != null && //this does not work
nth <= 8)
{
nth++;
//Do stuff
}
}
Structures do not inherit in C#, so ValueTuple<T1>, ValueTuple<T1,T2>, ValueTuple<T1,T2,T3> and so on are distinct types that do not inherit from ValueTuple as their base. Hence, obj is ValueTuple check fails.
If you are looking for ValueTuple with arbitrary type arguments, you can check if the class is ValueTuple<,...,> as follows:
private static readonly Set<Type> ValTupleTypes = new HashSet<Type>(
new Type[] { typeof(ValueTuple<>), typeof(ValueTuple<,>),
typeof(ValueTuple<,,>), typeof(ValueTuple<,,,>),
typeof(ValueTuple<,,,,>), typeof(ValueTuple<,,,,,>),
typeof(ValueTuple<,,,,,,>), typeof(ValueTuple<,,,,,,,>)
}
);
static bool IsValueTuple2(object obj) {
var type = obj.GetType();
return type.IsGenericType
&& ValTupleTypes.Contains(type.GetGenericTypeDefinition());
}
To get sub-items based on the type you could use an approach that is not particularly fast, but should do the trick:
static readonly IDictionary<Type,Func<object,object[]>> GetItems = new Dictionary<Type,Func<object,object[]>> {
[typeof(ValueTuple<>)] = o => new object[] {((dynamic)o).Item1}
, [typeof(ValueTuple<,>)] = o => new object[] {((dynamic)o).Item1, ((dynamic)o).Item2}
, [typeof(ValueTuple<,,>)] = o => new object[] {((dynamic)o).Item1, ((dynamic)o).Item2, ((dynamic)o).Item3}
, ...
};
This would let you do this:
object[] items = null;
var type = obj.GetType();
if (type.IsGeneric && GetItems.TryGetValue(type.GetGenericTypeDefinition(), out var itemGetter)) {
items = itemGetter(obj);
}
Regarding the part of the question "How can I get each item?"...
Both ValueTuple and Tuple both implement ITuple, which has a length property and an indexer property. So a the following console app code lists the values to the console:
// SUT (as a local function)
IEnumerable<object> GetValuesFromTuple(System.Runtime.CompilerServices.ITuple tuple)
{
for (var i = 0; i < tuple.Length; i++)
yield return tuple[i];
}
// arrange
var valueTuple = (StringProp: "abc", IntProp: 123, BoolProp: false, GuidProp: Guid.Empty);
// act
var values = GetValuesFromTuple(valueTuple);
// assert (to console)
Console.WriteLine($"Values = '{values.Count()}'");
foreach (var value in values)
{
Console.WriteLine($"Value = '{value}'");
}
Console output:
Values = '4'
Value = 'abc'
Value = '123'
Value = 'False'
Value = '00000000-0000-0000-0000-000000000000'
This is my solution to the problem. A PCL compatible extension class. Special thanks to #dasblinkenlight and #Evk for helping me out!
public static class TupleExtensions
{
private static readonly HashSet<Type> ValueTupleTypes = new HashSet<Type>(new Type[]
{
typeof(ValueTuple<>),
typeof(ValueTuple<,>),
typeof(ValueTuple<,,>),
typeof(ValueTuple<,,,>),
typeof(ValueTuple<,,,,>),
typeof(ValueTuple<,,,,,>),
typeof(ValueTuple<,,,,,,>),
typeof(ValueTuple<,,,,,,,>)
});
public static bool IsValueTuple(this object obj) => IsValueTupleType(obj.GetType());
public static bool IsValueTupleType(this Type type)
{
return type.GetTypeInfo().IsGenericType && ValueTupleTypes.Contains(type.GetGenericTypeDefinition());
}
public static List<object> GetValueTupleItemObjects(this object tuple) => GetValueTupleItemFields(tuple.GetType()).Select(f => f.GetValue(tuple)).ToList();
public static List<Type> GetValueTupleItemTypes(this Type tupleType) => GetValueTupleItemFields(tupleType).Select(f => f.FieldType).ToList();
public static List<FieldInfo> GetValueTupleItemFields(this Type tupleType)
{
var items = new List<FieldInfo>();
FieldInfo field;
int nth = 1;
while ((field = tupleType.GetRuntimeField($"Item{nth}")) != null)
{
nth++;
items.Add(field);
}
return items;
}
}
hackish one liner
type.Name.StartsWith("ValueTuple`")
(can be extended to check the digit at the end)

Get Property Value from Nested Objects - Efficient Ways than Reflection

My use case can have thousands of instances of a class. One of the properties in that class is also of the same type as that of a class and this can go on and on.
So I basically have a collection of nested classes. Now if I were to search a property's value, what would my options be.
I am finding recurssion as one(Getting Nested Object Property Value Using Reflection) and an exhaustive use of GetNestedTypes(https://msdn.microsoft.com/en-us/library/493t6h7t(v=vs.110).aspx) as other.
I read that reflection is expensive, so my question is, are there other ways to search the property without using reflection concept?
You can use expression trees to create an abstract syntax tree that you can then compile to a dynamic method. This performs very closely to regularly written code (from my testing it is many times faster then reflection). The creation of the dynamic method is expensive, so create once, use many times.
static Func<object,object> CreateDelegate(PropertyInfo[] path)
{
var rootType = path.First().DeclaringType;
var param = Expression.Parameter(typeof(object));
Expression access = Expression.Convert(param, rootType);
foreach (var prop in path)
{
access = Expression.MakeMemberAccess(access, prop);
}
var lambda = Expression.Lambda<Func<object, object>>(
Expression.Convert(access, typeof(object)),
param
).Compile();
return lambda;
}
static void Main(string[] args)
{
var path = new[]
{
typeof(Root).GetProperty("Level1"),
typeof(Level1).GetProperty("Level2"),
typeof(Level2).GetProperty("Name")
};
var method = CreateDelegate(path);
var data = new Root { Level1 = new Level1 { Level2 = new Level2 { Name = "Test" } } };
var result = method(data);
}
References: Dynamic Methods, Expression Tree-Compile

call method with params in arguments through reflection c#

Method return record from Database.
public T Find(params object[] primaryKeys)
{
var dbSet = _sessionContext.Set<T>() as DbSet<T>;
return dbSet != null ? dbSet.Find(primaryKeys) : null;
}
I'm trying to call in through reflection
var methodCreateReadRepositoryEntity =
typeof(IRepositoryFactory)
.GetMethod("CreateReadRepository")
.MakeGenericMethod(entityMetadata.GetEntityType());
var entityReadRepository =
methodCreateReadRepositoryEntity
.Invoke(_repositoryFactory, new object[] { _sessionMarketContext });
List<object> keys = new List<object>();
keys.Add(value);
var methodEntityGet =
entityReadRepository.GetType().GetMethod("Find", new Type[] { typeof(object[])});
var fromRepo =
methodEntityGet.Invoke(entityReadRepository, new object[]{new []{ keys.ToArray()[0]}});
value is Guid. And I have error
The type of one of the primary key values did not match the type defined in the entity.
Exception has been thrown by the target of an invocation.
Your last line should be as follows. You need to be explicit with the array type, and there is no need to create a List.
var fromRepo =
methodEntityGet.Invoke(entityReadRepository, new object[]{new object []{value}});

Foreach loop using Expression trees

I have seen this Issue while building dynamic Expression Tree and Expression/Statement trees and since I am new to expression trees I am still struggling to understand how to achieve what I want.
A contrived object is below
public class TestObject
{
public TestObject()
{
ClassList = new List<Class>();
}
public int Age { get; set; }
public List<Class> ClassList { get; set; }
}
public class Class
{
public string Name { get; set; }
public int ClassId { get; set; }
}
At run time I iterate through each of the properties and generate a Delegate which does a conversion to string of that property. I have got all that working. The issue I have to deal with now is that for the List type, I need to be able to apply a set of actions to each item in the ClassList property so I need a foreach which allows me to do that.
I currently have this
//type==TestObject at runtime
//propertyName == "ClassList"
ParameterExpression recordExpression = Expression.Parameter(type, "record");
memberExpression = MemberExpression.Property(recordExpression, propertyName);
Type getEnumerableDelegateType =
typeof(Func<,>).MakeGenericType(new Type[] { type, memberExpression.Type});
var getList = Expression.Lambda(getEnumerableDelegateType, memberExpression, recordExpression);
GetList when compiled and invoked returns the List as expected. What I m struggling with is how to create an expression which will use the result from the lambda expression and iterate over it applying the set of actions I have already created for each Class item.
Ultimately I am looking for a lambda signature to match the overallAction signature below
var getListFunc = new Func<TestObject, List<Class>>((TestObject obj1) => obj1.ClassList);
Action<List<Class>> listAction = delegate(List<Class> data)
{
foreach (var dataChannelWithUnitse in data)
{
//Apply generated delegate
}
};
Action<TestObject> overallAction = delegate(TestObject data)
{
var x = getListFunc.Invoke(data);
listAction.Invoke(x as List<Class>);
};
Any help is appreciated to help me understand how to do this.
I have currently got this which is exceptioning with variable 'Input' of type 'TestObject' referenced from scope '', but it is not defined
var typeParam = Expression.Parameter(type, "Input");
var listVariable = Expression.Variable(memberExpression.Type, "List");
var enumerator = Expression.Variable(typeof(IEnumerator<>).MakeGenericType(dataType));
var enumeratorType = typeof(IEnumerator<>).MakeGenericType(dataType);
var enumerableType = typeof(IEnumerable<>).MakeGenericType(dataType);
var enumerableParam = Expression.Parameter(enumerableType, "ExtractedCollection");
var getEnumeratorFunc = Expression.Call(enumerableParam, enumerableType.GetMethod("GetEnumerator"));
var getEnumeratorLambda = Expression.Lambda(getEnumeratorFunc, enumerableParam);
var t1 = Expression.Assign(listVariable, Expression.Invoke(getListLambda, typeParam));
var t2 = Expression.Assign(enumerator, Expression.Invoke(getEnumeratorLambda, listVariable));
var #break = Expression.Label();
var funcBlock = Expression.Block(
new ParameterExpression[] { listVariable, enumerator},
t1,
t2,
Expression.Loop(
Expression.IfThenElse(
Expression.NotEqual(Expression.Call(enumerator,typeof(IEnumerator).GetMethod("MoveNext")),Expression.Constant(false)),
Expression.Invoke(enumerableExpressions[0],Expression.Property(enumerator, "Current")),
Expression.Break(#break))
, #break), typeParam);
Expression<Action<TestObject>> lm = Expression.Lambda<Action<TestObject>>(funcBlock,recordExpression);
var d = lm.Compile(); **//this is exceptioning with " variable 'Input' of type 'TestObject' referenced from scope '', but it is not defined**
I got lost somewhere in the middle of your question (and if I've interpreted it incorrectly, please tell me, and I'll dive back into it), but I think this is what you're after:
public static Expression ForEach(Expression collection, ParameterExpression loopVar, Expression loopContent)
{
var elementType = loopVar.Type;
var enumerableType = typeof(IEnumerable<>).MakeGenericType(elementType);
var enumeratorType = typeof(IEnumerator<>).MakeGenericType(elementType);
var enumeratorVar = Expression.Variable(enumeratorType, "enumerator");
var getEnumeratorCall = Expression.Call(collection, enumerableType.GetMethod("GetEnumerator"));
var enumeratorAssign = Expression.Assign(enumeratorVar, getEnumeratorCall);
// The MoveNext method's actually on IEnumerator, not IEnumerator<T>
var moveNextCall = Expression.Call(enumeratorVar, typeof(IEnumerator).GetMethod("MoveNext"));
var breakLabel = Expression.Label("LoopBreak");
var loop = Expression.Block(new[] { enumeratorVar },
enumeratorAssign,
Expression.Loop(
Expression.IfThenElse(
Expression.Equal(moveNextCall, Expression.Constant(true)),
Expression.Block(new[] { loopVar },
Expression.Assign(loopVar, Expression.Property(enumeratorVar, "Current")),
loopContent
),
Expression.Break(breakLabel)
),
breakLabel)
);
return loop;
}
To use it, you need to supply a collection to iterate over, an expression to substitute into the body of the loop, and a ParameterExpression which is used by the loop body expression, which will be assigned to the loop variable on each loop iteration.
I think sometimes examples speak louder than words...
var collection = Expression.Parameter(typeof(List<string>), "collection");
var loopVar = Expression.Parameter(typeof(string), "loopVar");
var loopBody = Expression.Call(typeof(Console).GetMethod("WriteLine", new[] { typeof(string) }), loopVar);
var loop = ForEach(collection, loopVar, loopBody);
var compiled = Expression.Lambda<Action<List<string>>>(loop, collection).Compile();
compiled(new List<string>() { "a", "b", "c" });
EDIT: As Jeroem Mostert correctly points out in the comments, this doesn't quite mirror the "real" behaviour of a foreach loop: this would make sure that it disposes the enumerator. (It would also create a new instance of the loop variable for each iteration, but that doesn't make sense with expressions). Implementing this is just a matter of turning the handle if you feel motivated enough!
For anyone watching at home, I've got a similar method for generating 'for' loops:
public static Expression For(ParameterExpression loopVar, Expression initValue, Expression condition, Expression increment, Expression loopContent)
{
var initAssign = Expression.Assign(loopVar, initValue);
var breakLabel = Expression.Label("LoopBreak");
var loop = Expression.Block(new[] { loopVar },
initAssign,
Expression.Loop(
Expression.IfThenElse(
condition,
Expression.Block(
loopContent,
increment
),
Expression.Break(breakLabel)
),
breakLabel)
);
return loop;
}
This is equivalent to the following statement, where the pseudo-variables match the Expressions in the method above:
for (loopVar = initValue; condition; increment)
{
loopContent
}
Again, loopContent, condition, and increment are Expressions which uses loopVar, and loopVar is assigned on every iteration.
relatively_random's solution is great but foreach handles several other scenarios. Check these links to SharpLab to verify what is generated in each of them:
When the enumerable is a IEnumerable<T>, it checks if the enumerator is null before calling Dispose().
When the enumerable is not an interface, the enumerator changes to have the type returned by GetEnumerator(). The enumerator is cast to IDisposable before calling Dispose().
When the enumerator doesn't implement IDisposable, as is used on the check if the enumerator implements IDisposable. (???)
When the enumerator is a value type, the check for null goes away.
When the enumerator is a value type and doesn't implement IDisposable, the try/finally goes away.
The use of the type returned by GetEnumerator() is very important so that value type enumerators are not boxed. All the collections in System.Collections.Generic have value type enumerator because calls to its methods are not virtual, resulting in a lot better performance.
Putting all together results in the following code:
static partial class ExpressionEx
{
public static Expression ForEach<TSource>(Expression enumerable, Expression loopContent)
{
var enumerableType = enumerable.Type;
var getEnumerator = enumerableType.GetMethod("GetEnumerator");
if (getEnumerator is null)
getEnumerator = typeof(IEnumerable<>).MakeGenericType(typeof(TSource)).GetMethod("GetEnumerator");
var enumeratorType = getEnumerator.ReturnType;
var enumerator = Expression.Variable(enumeratorType, "enumerator");
return Expression.Block(new[] { enumerator },
Expression.Assign(enumerator, Expression.Call(enumerable, getEnumerator)),
EnumerationLoop(enumerator, loopContent));
}
public static Expression ForEach<TSource>(Expression enumerable, ParameterExpression loopVar, Expression loopContent)
{
var enumerableType = enumerable.Type;
var getEnumerator = enumerableType.GetMethod("GetEnumerator");
if (getEnumerator is null)
getEnumerator = typeof(IEnumerable<>).MakeGenericType(typeof(TSource)).GetMethod("GetEnumerator");
var enumeratorType = getEnumerator.ReturnType;
var enumerator = Expression.Variable(enumeratorType, "enumerator");
return Expression.Block(new[] { enumerator },
Expression.Assign(enumerator, Expression.Call(enumerable, getEnumerator)),
EnumerationLoop(enumerator,
Expression.Block(new[] { loopVar },
Expression.Assign(loopVar, Expression.Property(enumerator, "Current")),
loopContent)));
}
static Expression EnumerationLoop(ParameterExpression enumerator, Expression loopContent)
{
var loop = While(
Expression.Call(enumerator, typeof(IEnumerator).GetMethod("MoveNext")),
loopContent);
var enumeratorType = enumerator.Type;
if (typeof(IDisposable).IsAssignableFrom(enumeratorType))
return Using(enumerator, loop);
if (!enumeratorType.IsValueType)
{
var disposable = Expression.Variable(typeof(IDisposable), "disposable");
return Expression.TryFinally(
loop,
Expression.Block(new[] { disposable },
Expression.Assign(disposable, Expression.TypeAs(enumerator, typeof(IDisposable))),
Expression.IfThen(
Expression.NotEqual(disposable, Expression.Constant(null)),
Expression.Call(disposable, typeof(IDisposable).GetMethod("Dispose")))));
}
return loop;
}
public static Expression Using(ParameterExpression variable, Expression content)
{
var variableType = variable.Type;
if (!typeof(IDisposable).IsAssignableFrom(variableType))
throw new Exception($"'{variableType.FullName}': type used in a using statement must be implicitly convertible to 'System.IDisposable'");
var getMethod = typeof(IDisposable).GetMethod("Dispose");
if (variableType.IsValueType)
{
return Expression.TryFinally(
content,
Expression.Call(Expression.Convert(variable, typeof(IDisposable)), getMethod));
}
if (variableType.IsInterface)
{
return Expression.TryFinally(
content,
Expression.IfThen(
Expression.NotEqual(variable, Expression.Constant(null)),
Expression.Call(variable, getMethod)));
}
return Expression.TryFinally(
content,
Expression.IfThen(
Expression.NotEqual(variable, Expression.Constant(null)),
Expression.Call(Expression.Convert(variable, typeof(IDisposable)), getMethod)));
}
public static Expression While(Expression loopCondition, Expression loopContent)
{
var breakLabel = Expression.Label();
return Expression.Loop(
Expression.IfThenElse(
loopCondition,
loopContent,
Expression.Break(breakLabel)),
breakLabel);
}
}
The ForEach without loopVar is useful to enumerate without getting the items. That's the case of Count() implementation.
EDIT: An updated and tested version is available in the NetFabric.Reflection NuGet package. Check its repository for the source code.
Here's a slightly expanded version of canton7's excellent solution, taking into account the remarks about disposing the enumerator:
public static Expression ForEach(Expression enumerable, ParameterExpression loopVar, Expression loopContent)
{
var elementType = loopVar.Type;
var enumerableType = typeof(IEnumerable<>).MakeGenericType(elementType);
var enumeratorType = typeof(IEnumerator<>).MakeGenericType(elementType);
var enumeratorVar = Expression.Variable(enumeratorType, "enumerator");
var getEnumeratorCall = Expression.Call(enumerable, enumerableType.GetMethod("GetEnumerator"));
var enumeratorAssign = Expression.Assign(enumeratorVar, getEnumeratorCall);
var enumeratorDispose = Expression.Call(enumeratorVar, typeof(IDisposable).GetMethod("Dispose"));
// The MoveNext method's actually on IEnumerator, not IEnumerator<T>
var moveNextCall = Expression.Call(enumeratorVar, typeof(IEnumerator).GetMethod("MoveNext"));
var breakLabel = Expression.Label("LoopBreak");
var trueConstant = Expression.Constant(true);
var loop =
Expression.Loop(
Expression.IfThenElse(
Expression.Equal(moveNextCall, trueConstant),
Expression.Block(
new[] { loopVar },
Expression.Assign(loopVar, Expression.Property(enumeratorVar, "Current")),
loopContent),
Expression.Break(breakLabel)),
breakLabel);
var tryFinally =
Expression.TryFinally(
loop,
enumeratorDispose);
var body =
Expression.Block(
new[] { enumeratorVar },
enumeratorAssign,
tryFinally);
return body;
}

Cast List<object> to AnonymousTypes list

I have populated the follow list with objects of type AnonymousType
List<object> someList = new List<object>();
someList.Add(new { foo = 1 });
My problem is that I can't make it stronly typed to do something like this:
someList.Where(x=> x.foo == 1);
However, it's possible on this list:
var someList = new[] { new { foo = 1 } };
Can I cast my first list to make it behave like the second list? I want to be able to use lambda expressions on the properties like I showed above.
You can take advantage of generics and type inference to create the list for you:
public static List<T> CreateAnonymousList<T>(params T[] entries)
{
return new List<T>(entries);
}
Usage like:
var someList = CreateAnonymousList(new { foo = 1 }, new { foo = 2 }, new { foo = 1 });
someList.Where(x => x.foo == 1);
Naturally you won't be able to do much with it. You'll never be able to strongly type it in your code to anything other than var or return it out from your method or anything you normally wouldn't be able to do with anonymous types. If you want to do more, you'll just have to bite the (small) bullet and define a class for your anonymous type.
Rereading your question, you can still perform LINQ queries on an array:
var someArray = new[]{new { foo = 1 }, new { foo = 2 }, new { foo = 1 }};
someArray.Where(x => x.foo == 1)
So unless you are modifying it (say via standard List<T> operations like Add or Remove) then there's no reason to have to convert it to a List<T>.
I realize that maybe you want to still be able to pass it back (for some reason) and still do operations on it without knowing its anonymous type. In that case you could treat it as dynamic and perform the operations at runtime, but you lose any intellisense/strong typing that you'd normally have with the anonymous type:
List<dynamic> someDynamicList = new List<dynamic>() {new { foo = 1 }, new { foo = 2 }, new { foo = 1 }};
someDynamicList.Where(x => x.foo == 1)
One last method as pointed out by Tim Schmelter leveraging Jon Skeet's CastByExample, but extended to convert your collection with an extension method:
public static IEnumerable<T> CastByExample<T>(this IEnumerable source, T example)
{
foreach(object entry in source)
yield return (T)entry;
}
public static IEnumerable CreateAnonymousData()
{
return new[]{new { foo = 1 }, new { foo = 2 }, new { foo = 1 }};
}
With usage like:
var anonymousData = CreateAnonymousData();
var typedAnonymousData = anonymousData.CastByExample(new { foo = 1 });
typedAnonymousData.Where(x => x.foo == 1);
This takes advantage of the fact that within the same assembly, anonymous types declared with the same parameter names, types, and order compile to the same type. This won't work if you need to call your CreateAnonymousData from outside the current assembly and you have to maintain the signature of your foo anonymous type everywhere you use it (add/change its signature, you must update it everywhere you use it or you're going to have a bad time).
But I think it's becoming more clear now that the best solution to this is to simply define a class representation of your anonymous type.
You can use Jon Skeets' CastByExample:
public static T CastByExample<T>(object input, T example)
{
return (T)input;
}
List<object> someList = new List<object>() {
new { foo = 1 },new { foo = 2 },new { foo = 3 }
};
var example = new { foo = 0 };
foreach (object obj in someList)
{
var x = CastByExample(obj, example);
Console.WriteLine("Foo: " + x.foo);
}

Categories