c# - Linq 反射表达式对属性的属性抛出异常
问题描述
我正在尝试使用 Linq Expressions 参数创建函数,但遇到了问题。
这是我的测试功能:
public static void OutputField(Person p, Expression<Func<Person, string>> outExpr)
{
var expr = (MemberExpression)outExpr.Body;
var prop = (PropertyInfo)expr.Member;
string v = prop.GetValue(p, null).ToString();
Console.WriteLine($"value={v}");
}
如果我将 Person 对象定义为
public class Person
{
public PersonName Name { get; set; }
public string City { get; set; }
}
public class PersonName
{
public string First { get; set; }
public string Last { get; set; }
}
并尝试以这种方式使用它
Person person = new Person
{
Name = new PersonName { First = "John", Last = "Doe" },
City = "New York City"
};
OutputField(person, m => m.City);
OutputField(person, m => m.Name.First);
属性 City 的输出有效,但属性 First of the property Name 的输出抛出System.Reflection.TargetException: 'Object does not match target type。错误。如何使我的测试功能工作?
CSharpie 指出的“组合 lambda 表达式以检索嵌套值”似乎正在解决类似的问题,但尚不清楚我将如何将答案应用于我的函数。
解决方案
错误是您Person
在prop.GetValue
访问PersonName.First
. 该方法试图从中获取属性First
,Person
但不能。您需要将正确的对象传递到prop.GetValue
. 我制作了这种通用方法,可以实现您想要的。一个限制是它只检查字段和属性,我会尝试添加一些方法
public static void OutputField < T > (T item, Expression < Func < T, string >> outExpr)
{
// Get the expression as string
var str = outExpr.ToString();
// Get the variable of the expresion (m, m => ...)
string pObj = str.Substring(0, str.IndexOf(' '));
// Get all the members in the experesion (Name, First | m.Name.First);
string[] members = new string(str.Skip(pObj.Length * 2 + 5).ToArray()).Split('.');
// Last object in the tree
object lastMember = item;
// The type of lastMember
Type lastType = typeof(T);
// Loop thru each member in members
for (int i = 0; i < members.Length; i++)
{
// Get the property value
var prop = lastType.GetProperty(members[i]);
// Get the field value
var field = lastType.GetField(members[i]);
// Get the correct one and set it as last member
if (prop is null)
{
lastMember = field.GetValue(lastMember);
}
else
{
lastMember = prop.GetValue(lastMember, null);
}
// Set the type of the last member
lastType = lastMember.GetType();
}
// Print the value
Console.WriteLine($ "value={lastMember}");
}
编辑: 原来你可以编译表达式并调用它
public static void OutputField<T>(T item, Expression<Func<T, string>> outExpr)
{
Console.WriteLine($"value={outExpr.Compile().Invoke(item)}");
}
推荐阅读
- java - 带有自定义配置器的 Spring 406
- javascript - 不能将下拉菜单的 innerHTML 设置为等于数组的变量
- javascript - 在jQuery中处理多个复选框
- python - 降维后使用选定变量会引发值错误
- python - 当我点击两个点时,有没有办法绘制一个特定的值?
- ios - 一旦我在嵌套 CollectionView 的内部 CollectionView 中添加约束,它就会开始一个永无止境的循环
- apache-spark - Spark 驱动程序中的内存泄漏
- java - vsd文件下载问题
- javascript - 如何在猫鼬中查询对象数组内的值
- android - 我如何从任何网站构建原生 android 应用程序(不是网站转换为应用程序)