C#中如何用表达式创建泛型列表并调用Add、ToArray方法?
问题描述
我想编写一个UserData类,用来把任意用户自定义类存储到强类型列表中。比如用户自定义类可以是:
class UserInfo { public int Id {get;set;} // 其他属性 }
或者
class BookInfo { public Guid BookId {get;set;} public string BookName {get;set;} // 其他属性 }
我自己写的UserData类大致如下:
internal class UserData { private readonly bool _isCollection; private readonly Type _userEntityType; private Expression _list; private someDelegeAdd _add; private someDelegeToArray _ToArray; public UserData(bool isCollection, Type userEntityType) { _isCollection = isCollection; _userEntityType = userEntityType; Make(); } private void Make() { var genericListType = typeof(List<>).MakeGenericType(_userEntityType); _list = Expression.New(genericListType); var addDefinition = genericListType.GetMethod("Add", new[] { _userEntityType }); var parameter = Expression.Parameter(_userEntityType); var addMethodExp = Expression.Call(_list, addDefinition, parameter); _add = Expression.Lambda<Action>(addMethodExp, parameter).Compile(); // 这里的Action有问题 } internal void Add(object data) { // 不知道怎么调用_add } internal object GetValue() { return _isCollection ? _list?? : _ToArray?? ; // 不知道怎么处理ToArray } }
我搜了很久,只找到Func<T,X>相关的委托示例,不清楚怎么创建对应任意类型的Action委托,同时也不知道如何通过表达式调用ToArray方法。
---更新---
使用示例:
if (!cache.Contains(userEntityType)) { var userData = new UserData(false, userEntityType); // 后续操作 }
解决方案
1. 核心修正点
- 把
_list从Expression类型改为存储实际的强类型List实例(用object类型承载,因为编译期无法确定泛型参数) - 用
Action<object>存储Add委托,直接兼容外部传入的object类型参数 - 通过反射获取
Enumerable.ToArray<T>方法,构建转换数组的委托
完整修正代码
internal class UserData { private readonly bool _isCollection; private readonly Type _userEntityType; private object _listInstance; // 存储实际的强类型List实例 private Action<object> _addAction; // 处理Add逻辑的委托 private Func<object> _toArrayFunc; // 处理ToArray逻辑的委托 public UserData(bool isCollection, Type userEntityType) { _isCollection = isCollection; _userEntityType = userEntityType; Initialize(); } private void Initialize() { // 创建强类型List实例 var genericListType = typeof(List<>).MakeGenericType(_userEntityType); _listInstance = Activator.CreateInstance(genericListType); // 构建Add委托:将object参数转换为目标类型后调用List.Add var addMethod = genericListType.GetMethod("Add", new[] { _userEntityType }); var addParam = Expression.Parameter(typeof(object), "data"); var convertedParam = Expression.Convert(addParam, _userEntityType); var addCall = Expression.Call(Expression.Constant(_listInstance), addMethod, convertedParam); _addAction = Expression.Lambda<Action<object>>(addCall, addParam).Compile(); // 构建ToArray委托:调用Enumerable.ToArray<T>转换List为数组 var toArrayMethod = typeof(Enumerable).GetMethod("ToArray") .MakeGenericMethod(_userEntityType); var toArrayCall = Expression.Call(toArrayMethod, Expression.Constant(_listInstance)); _toArrayFunc = Expression.Lambda<Func<object>>(toArrayCall).Compile(); } internal void Add(object data) { _addAction?.Invoke(data); } internal object GetValue() { // 根据_isCollection标记返回List实例或数组 return _isCollection ? _listInstance : _toArrayFunc?.Invoke(); } }
关键逻辑说明
- List实例创建:直接用
Activator.CreateInstance生成强类型List实例,比表达式树更简洁直接 - Add委托处理:通过
Expression.Convert自动完成object到目标实体类型的转换,兼容外部传入的任意对象 - ToArray委托处理:反射获取泛型的
ToArray方法,针对当前实体类型构建具体调用,最终返回强类型数组(以object形式承载)
实际使用示例
// 假设cache是存储UserData的字典 var cache = new Dictionary<Type, UserData>(); var userEntityType = typeof(UserInfo); if (!cache.ContainsKey(userEntityType)) { var userData = new UserData(false, userEntityType); cache.Add(userEntityType, userData); } // 添加数据 var userInfo = new UserInfo { Id = 1001 }; cache[userEntityType].Add(userInfo); // 获取转换后的数组 var userArray = (UserInfo[])cache[userEntityType].GetValue();
内容的提问来源于stack exchange,提问作者user1814688
相关产品推荐
相关产品推荐

