给定一个表达式,例如:
m => m.Employee.Address.Line1
我需要创建一个函数,它可以遍历表达式,提取所涉及的对象,或者至少是链中的最终对象(即上面的地址对象)。所以对于上面的例子,函数会发现:
- “这里”是 m 参数的实例(我可以从中获取类型)
- “这里”是 Employee 成员的实例
- (即重复链条)
目的是能够为“路径”生成配置信息。
如果我至少可以得到最终的“包含”对象,那么我可以产生类型信息,如果它支持特定的属性或方法,则可以调用该对象,以向对象请求额外的配置信息(以及要获取的对象类型)容器类型的配置信息)。
即使是稍微复杂一点的语句也会使这变得更加困难,例如:
m.Employee.Address[i].Line1
--- 只是为了提供一个我在 MVC 中为 BASIC 场景工作的示例。下面的 GetContainingModel() 在加载的 DataAnnotationsMetadataProvider 中的 CreateMetadata() 中被调用。传递给 CreateMetadata() 的模型是 Lambda 语句根的模型,并不是我们真正想要的。所以逻辑试图找到最终的包含对象。我宁愿不要像我正在做的那样使用反射,或者更糟的是,接触到一个私人成员(不好),但是......我愿意接受建议。
[TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
private object GetContainingModel()
{
if (_metadata == null)
{
throw new SystemException("Unexpected NULL Metadata");
}
var model = _metadata.Model;
try
{
if (_modelAccessor != null)
{
var data = _modelAccessor.Target;
if (data != null)
{
if (GetModelFromContainer(data, ref model))
{
GetModelFromExpression(data, ref model);
}
}
}
}
catch (Exception ex)
{
var msg = ex.Message;
}
return model;
}
[TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
private bool GetModelFromContainer(object data, ref object model)
{
var isSet = false;
var container = data.GetType().GetField("container");
if (container != null)
{
model = container.GetValue(data);
isSet = true;
}
else
{
var vdi = data.GetType().GetField("vdi");
if (vdi != null)
{
var viewDataInfo = vdi.GetValue(data) as ViewDataInfo;
if (viewDataInfo != null)
{
model = viewDataInfo.Container;
isSet = true;
}
}
}
return isSet && model != null;
}
[TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
private bool GetModelFromExpression(object data, ref object model)
{
if (model == null)
return false;
var expressionField = data.GetType().GetField("expression");
if (expressionField == null)
return false;
return GetModelFromExpression(expressionField.GetValue(data) as LambdaExpression, ref model);
}
[TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
private bool GetModelFromExpression(LambdaExpression sourceExpression, ref object model)
{
if (sourceExpression == null)
return false;
var expressionBody = sourceExpression.Body as MemberExpression;
if (expressionBody == null || expressionBody.NodeType != ExpressionType.MemberAccess || expressionBody.Member == null)
return false;
var expression = expressionBody.Expression as MemberExpression;
if (expression == null)
{
return false;
}
switch (expression.Member.MemberType)
{
case MemberTypes.Field:
if (expression.NodeType == ExpressionType.MemberAccess)
{
var fieldInfo = (FieldInfo)expression.Member;
if (fieldInfo != null)
{
model = fieldInfo.GetValue(model);
}
}
break;
case MemberTypes.Property:
var propertyInfo = (PropertyInfo)expression.Member;
if (propertyInfo != null)
{
model = propertyInfo.GetValue(model, null);
}
break;
}
return model != null;
}