场景

从接口返回的数据是集合,却是 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 indexProperty = type.GetDefaultMembers().OfType<PropertyInfo>()
.First(_ => _.GetIndexParameters().Any(_ => _.ParameterType == typeof(int))); // 方法二
//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, Expression.MakeIndex(convertExp, indexProperty, new ParameterExpression[] { tempVariableExp })), // 方法二
//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)}");
}

Expression Tree 遍历集合的更多相关文章

  1. Reflection和Expression Tree解析泛型集合快速定制特殊格式的Json

    很多项目都会用到Json,而且大部分的Json都是格式固定,功能强大,转换简单等,标准的key,value集合字符串:直接JsonConvert.SerializeObject(List<T&g ...

  2. 【C#表达式树 开篇】 Expression Tree - 动态语言

    .NET 3.5中新增的表达式树(Expression Tree)特性,第一次在.NET平台中引入了"逻辑即数据"的概念.也就是说,我们可以在代码里使用高级语言的形式编写一段逻辑, ...

  3. 深入学习C#匿名函数、委托、Lambda表达式、表达式树类型——Expression tree types

    匿名函数 匿名函数(Anonymous Function)是表示“内联”方法定义的表达式.匿名函数本身及其内部没有值或者类型,但是可以转换为兼容的委托或者表达式树类型(了解详情).匿名函数转换的计算取 ...

  4. Lambda表达式遍历集合

    1.Collection Java 8 为Iterable接口新增了一个forEach(Consumer action)默认方法,该方法所需参数的类型是一个函数式接口,而Iterable接口是Coll ...

  5. Expression Tree Basics 表达式树原理

    variable point to code variable expression tree data structure lamda expression anonymous function 原 ...

  6. Expression Tree 扩展MVC中的 HtmlHelper 和 UrlHelper

    表达式树是LINQ To everything 的基础,同时各种类库的Fluent API也 大量使用了Expression Tree.还记得我在不懂expression tree时,各种眼花缭乱的A ...

  7. 使用Expression Tree构建动态LINQ查询

    这篇文章介绍一个有意思的话题,也是经常被人问到的:如何构建动态LINQ查询?所谓动态,主要的意思在于查询的条件可以随机组合,动态添加,而不是固定的写法.这个在很多系统开发过程中是非常有用的. 我这里给 ...

  8. JAVA基础学习之final关键字、遍历集合、日期类对象的使用、Math类对象的使用、Runtime类对象的使用、时间对象Date(两个日期相减)(5)

    1.final关键字和.net中的const关键字一样,是常量的修饰符,但是final还可以修饰类.方法.写法规范:常量所有字母都大写,多个单词中间用 "_"连接. 2.遍历集合A ...

  9. .NET Expression Tree

    Expression Tree 第一个简单的例子. [TestMethod] public void GodTest() { Expression<Func<int, int, int&g ...

随机推荐

  1. wpf 中的 自定义控件的 binding

    XMl 代码 --------------------------------------------------------------------------------------------- ...

  2. java8 lambda表达式和函数式编程

    什么是函数式接口(Functional Interface) 其实之前在讲Lambda表达式的时候提到过,所谓的函数式接口,当然首先是一个接口,然后就是在这个接口里面只能有一个抽象方法 (可以有def ...

  3. Android Studio 百度地图导航

    配置就不再多说了,上一篇已经详细说过了,这次就是根据经纬度坐标做地图导航,路径规划.直接上代码: package com.example.appview.mian_page.Frament.Anzhu ...

  4. VS2017 提示找不到某个.dll库,或某个dll库丢失,原因

    可能因为那个dll的确不存在 可能因为需要在环境变量->系统环境变量->添加该dll所在目录

  5. volatile的基本原理

    volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java 5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果.在Java 5之后,volatile关键字才得以 ...

  6. Spring系列之Mybatis动态代理实现全过程?回答正确率不到1%

    面试中,可能会问到Spring怎么绑定Mapper接口和SQL语句的.一般的答案是Spring会为Mapper生成一个代理类,调用的时候实际调用的是代理类的实现.但是如果被追问代理类实现的细节,很多同 ...

  7. GoLang设计模式06 - 对象池模式

    这次介绍最后一个创建型模式--对象池模式.顾名思义,对象池模式就是预先初始化创建好多个对象,并将之保存在一个池子里.当需要的时候,客户端就可以从池子里申请一个对象使用,使用完以后再将之放回到池子里.池 ...

  8. web安全性测试——XSS跨站攻击

    1.跨站攻击含义 XSS:(Cross-site scripting)全称"跨站脚本",是注入攻击的一种.其特点是不对服务器端造成任何伤害,而是通过一些正常的站内交互途径,例如发布 ...

  9. Linux 网卡驱动sk_buff内核源码随笔

    这几天在调试有关网卡驱动的东西,有很多地方不清楚.有关网卡驱动部分主要有两个很重要的结构体:struct net_device 和struct sk_buff. 驱动大部分都是围绕这两个东西进行操作的 ...

  10. shell脚本获取文件名、路径名、文件类型

    1. 从字符串获取指定内容 从字符串中提取特定的信息,常用于获取文件名.文件类型.所在路径等. 1.1 获取字符串信息 用指定的方式(PATTERN)从字符串(PARAMETERS)中移除内容 &qu ...