场景
从接口返回的数据是集合,但是 object 类型的。这个时候需要遍历这个集合。现提供两种方法。
方法一:
因为集合是可枚举的,所以可以尝试转为 IEnumerable 类型,然后遍历即可。
static void Main(string[] args) { var list = new List<Foo> { new Foo{ Id = 1, Name = "aaa" }, new Foo{ Id = 2, Name = "bbb" }, new Foo{ Id = 3, Name = "ccc" } }; ReflectionCollection(list); } private static void ReflectionCollection(object input) { var collection = input as IEnumerable; if (collection is not null) { var enumerator = collection.GetEnumerator(); while (enumerator.MoveNext()) { Console.WriteLine($"{JsonSerializer.Serialize(enumerator.Current)}"); } } }
方法二:
使用表达式树。
private static void ExpressionTreeAccessCollection(object input) { var type = input.GetType(); var inputParameterExp = Expression.Parameter(typeof(object), "input"); var callbackParameterExp = Expression.Parameter(typeof(Action<object>), "callback"); var countVariableExp = Expression.Variable(typeof(int), "count"); var tempVariableExp = Expression.Variable(typeof(int)); var itemVariableExp = Expression.Variable(typeof(object), "item"); var convertExp = Expression.Convert(inputParameterExp, type); var voidLabel = Expression.Label(); var toArrayMethod = type.GetMethod(nameof(List<object>.ToArray)); var toArrayExp = Expression.Call(convertExp, toArrayMethod); var arrayIndexExp = Expression.ArrayIndex(toArrayExp, new Expression[] { tempVariableExp }); //var printItemMethod = typeof(Program).GetMethod(nameof(PrintItem), BindingFlags.NonPublic | BindingFlags.Static); var blockExp = Expression.Block( new ParameterExpression[] { countVariableExp, tempVariableExp, itemVariableExp }, Expression.Assign( countVariableExp, Expression.Property(convertExp, "Count") ), Expression.Assign(tempVariableExp, Expression.Constant(0)), Expression.Loop( Expression.IfThenElse( Expression.LessThan(tempVariableExp, countVariableExp), Expression.Block( new ParameterExpression[] { itemVariableExp }, Expression.Assign(itemVariableExp, arrayIndexExp), //Expression.Call(null, printItemMethod, itemVariableExp), Expression.Invoke(callbackParameterExp, itemVariableExp), Expression.AddAssign(tempVariableExp, Expression.Constant(1, typeof(int))) ), Expression.Block( Expression.Return(voidLabel) ) ) ), Expression.Label(voidLabel) ); var lambda = Expression.Lambda<Action<object, Action<object>>>(blockExp, new ParameterExpression[] { inputParameterExp, callbackParameterExp }); var func = lambda.Compile(); func(input, item => { Console.WriteLine($"Callback: {JsonSerializer.Serialize(item)}"); }); }
private static void PrintItem(object item)
{
Console.WriteLine($"PrintItem: {JsonSerializer.Serialize(item)}");
}