Linq 里可以返回匿名类,这个很好用,自己的ORM里也想实现同样的功能,但赋值的时候发现匿名类的属性是Readonly的,晕了,Linq是怎么实现的呢?
简单写个示意代码如下:
简单建个Customer实体类。
class Customer { public string FirstName { get; set; } public string LastName { get; set; } }
做个Select方法:
class Entity<T> { public static Tresult MySelect<Tresult>(Expression<Func<T, Tresult>> func) { Type type = typeof(Tresult); Tresult t = (Tresult)Activator.CreateInstance(type, new object[type.GetProperties().Length]); object someValue = "";// 具体值不写了,只是做个样子 foreach (PropertyInfo pi in type.GetProperties()) { pi.SetValue(t, someValue, null); // 问题就出在这里了,如果是匿名类的话,没有Set方法。 } return t; } }
调用:
var cus = Entity<Customer>.MySelect(s => new { MyName = s.FirstName, YourName = s.LastName });
cus是我想要的匿名类,这个没问题,也是我想要的结果。不过在Select中构建这个匿名类时不能用SetValue的方法,说没有Set Method,我查了一下MSDN,里面说匿名类的Property是Readonly的,那这样的话,应该如何进行赋值呢? 是我的出发点错了吗?不用反射的话,有没有其他方法?
请有经验的朋友帮帮忙,先谢谢了。
-----------------------------------------------------
想到了一个办法,在构建这个类时,就把值赋好了。
代码如下:
object[] objArr = new object[type.GetProperties().Length]; for (int i=0;i<type.GetProperties().Length;i++) { objArr[i] = someValue..... } return (T)Activator.CreateInstance(type, objArr);
这样基本满足我的要求了,效率还没测,回头测试一下。大家如果有更好的办法,请补充,谢谢。
不知道你为什么要去set匿名类型的值,TResult 难道不应该是func自己执行的返回值吗,为什么需要你去操心呢。。LINQ以及你的MySelect方法应该是这么实现的:
public static Tresult MySelect<Tresult>(Expression<Func<T, Tresult>> func) { //一些不重要的代码 return func.Compile()(this.Data); } //其中this.Data是你Entity<T>实例返回T模型的一个属性
试了下用这样就可以了
public static TResult MySelect<TResult>(Expression<Func<T,TResult>> func) { return func.Compile()(Activator.CreateInstance<T>()); }
private void Test() { var cus = Entity<Customer> .Select(custom => new { MyName = custom.FirstName, YourName = custom.LastName }); } private static TR Select<TR>(Expression<Func<Customer, TR>> expression) { var someValue = "";// 具体值不写了,只是做个样子 var custom = new Customer { FirstName = "fuck", LastName = someValue }; return expression.Compile()(custom); }