这个问题是这个问题here的延续。如果有人想知道为什么我需要做这样的事情,你可以在这个问题中找到理由。不重要,真的。
我需要一个像这样的方法:
public virtual Expression<Func<T, object>> UpdateCriterion()
{
// this doesn't work because the compiler doesn't know if T has Id & CompanyId
return e => new { e.Id, e.CompanyId };
}
问题是,T
没有超级用户可以用来提取Id
和CompanyId
,我必须动态执行。由于对该引用问题的回答,我已经成功地为一个属性(e => e.Id
)构建并使用了这种方法,但是我在实现两个属性时遇到了问题。仅为了可见性,一个字段的解决方案是:
public virtual Expression<Func<T, object>> UpdateCriterion()
{
var param = Expression.Parameter(typeof(T));
var body = Expression.Convert(Expression.Property(param, "ID"), typeof(object));
return Expression.Lambda<Func<T, object>>(body, param);
}
我已经坚持了6个多小时......所以,我该如何解决这个问题呢?
答案 0 :(得分:1)
此Lamba的正文是MemerInitExpression。
这很容易。这里更大的问题是你在Lambda中使用匿名类型。
Expression<Func<TranslatedText, object>> exp;
exp = p => new { p.LanguageId, p.TextId};
如果您使用这样的AnonymousType,编译器将检查您的代码,检测AnonymousType声明并在运行中创建类似这样的类型。
public class f__AnonymousType0
{
public int LanguageId { get; set; }
public int TextId { get; set; }
}
将你的lambda改成这样的东西。
exp = p => new f__AnonymousType0 { LanguageId = p.LanguageId, TextId = p.TextId };
因为您想在运行时创建lambda,所以MemberInitExpression所需的f__AnonymousType0类型不存在。
由于您需要一个实际的类型来创建此表达式,因此您有两个选项可以获得一个。
1 - 编写一些泛型类,如.NET Framework的Tuple类。在核心中,此解决方案仅限于最大数量的属性。
pro:易于创建和使用 - con:有限的属性数。
public class KeyTuple<T1, T2>
{
public T1 Item1 { get; set; }
public T2 Item2 { get; set; }
}
public class KeyTuple<T1, T2, T3>
{
public T1 Item1 { get; set; }
public T2 Item2 { get; set; }
public T3 Item3 { get; set; }
}
public class KeyTuple<T1, T2, T3>
public class KeyTuple<T1, T2, T3, T4>
public class KeyTuple<T1, T2, T3, T4, T5>
public class KeyTuple<T1, T2, T3, T4, T5, T6>
2 - 您可以使用Reflection.Emit并在运行时创建一个类型 http://www.codeproject.com/Articles/121568/Dynamic-Type-Using-Reflection-Emit
亲:无限制的财产数量 - con:复杂
当你有一个类型时,你可以使用你已经知道的表达式树api来创建lambda
var keys = new[] { "LanguageId", "TextId" };
var param = Expression.Parameter(typeof(TranslatedText));
var properties = keys.Select(p => Expression.Property(param, p)).ToList();
var keyTupleType = typeof(KeyTuple<,>).Assembly.GetType(string.Format("AnonymousTypeExpression.KeyTuple`{0}",keys.Count()));
keyTupleType = keyTupleType.MakeGenericType(properties.Select(p => p.Type).ToArray());
var bindings = properties.Select((p,i) => Expression.Bind(keyTupleType.GetProperty(string.Format("Item{0}",i + 1)),p)).ToArray();
var body = Expression.MemberInit(Expression.New(keyTupleType), bindings);
var result= Expression.Lambda<Func<TranslatedText, object>>(body, param);
这会创建一个类似于此
的表达式exp = p => new KeyTuple<int, int> { Item1 = p.LanguageId, Item2 = p.TextId };
答案 1 :(得分:0)
尝试使用反射?
请不要在我面前没有视觉工作室或任何其他IDE,所以我的代码包含一些错误和错别字
另请注意,如果您不需要properties
,则可能需要fields
GetField()
并GetFields()
查看它们。
public virtual Expression<Func<T, object>> UpdateCriterion()
{
return e => new { GetPropertyValue<T>(e,"id"), GetPropertyValue<T>(e,"CompanyId") };
}
public object GetPropertyValue<T>(T TargetObject,string PropertyName)
{
var prop = typeof(T).GetProperty(PropertyName).GetValue(TargetObject, null);
}