编辑:简化问题可以在下面找到真实版本,但也许没有必要回答这个问题。
我有一个MethodCallExpression,我想重新调整一下。表达式调用的主体引用的方法是正确的方法,但是,其中一个类型参数将发生更改。给定一个现有的MethodCallExpression,我想构造一个新的MethodCallExpression,它具有相同的body表达式但是不同的类型参数。这可能吗?如何实现这一目标?感谢。
真实世界的问题(除非你需要更具体的例子,否则忽略这一点):
我有一个表达式Expression<Func<HtmlHelper<TModel>, Expression<Func<TModel, TValue>>, MvcHtmlString>>
,用作显示模板(将HtmlHelper和Expression&gt;作为输入并输出McvHtmlString)。如果TValue是一个自定义类实例,那么它的属性必须被输入到表达式委托而不是对象本身。这是有问题的,因为这意味着TValue将从父对象更改为当前属性的类型。 (代码如下)
我不确定如何解决这个问题。我理解ExpressionVisitor可用于实现表达式的这种改变,但我也在考虑我的表达式可能过于冗长的事实。请帮忙。
我正在尝试创建的是用于呈现标签/值字段对的HtmlHelper扩展方法(ASP.NET MVC)。但是,我有绑定和未绑定字段的概念。简单地使用一些挖空属性渲染绑定字段。这很有效,直到我尝试使用C#Expression API重构一些可重用的组件。
首先,这里有两个公共扩展方法,用于将字段集呈现为绑定或未绑定元素。
public static class HtmlHelperExtensions
{
public static MvcHtmlString FieldsetDisplayFor<TModel, TValue>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TValue>> expression)
{
return RenderFieldsetDisplayFor(htmlHelper, expression, (helper, ex) => helper.DisplayFor(ex));
}
public static MvcHtmlString BoundFieldsetDisplayFor<TModel, TValue>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TValue>> expression)
{
return RenderFieldsetDisplayFor(htmlHelper, expression, (helper, ex) => helper.BoundDisplayFor(ex));
}
// ...
}
注意传递给RenderFieldsetDisplayFor方法的两个不同表达式。这本质上是一个委托,低级方法将用于呈现如下所示的值:
internal static MvcHtmlString RenderFieldsetDisplayFor<TModel, TValue>(this HtmlHelper<TModel> htmlHelper,
Expression<Func<TModel, TValue>> expression,
Expression<Func<HtmlHelper<TModel>, Expression<Func<TModel, TValue>>, MvcHtmlString>> displayDelegate)
{
if (expression.ReturnType.IsContainerObject())
{
return DisplayChildFieldsetsFor(expression, htmlHelper, displayDelegate);
}
var labelBuilder = new TagBuilder("div");
labelBuilder.AddCssClass("display-label");
labelBuilder.InnerHtml = htmlHelper.LabelFor(expression).ToHtmlString();
var inputBuilder = new TagBuilder("div");
inputBuilder.AddCssClass("display-field");
// expression delegate called here for the rendering display of the value
inputBuilder.InnerHtml = displayDelegate.Compile().Invoke(htmlHelper, expression).ToHtmlString();
return new MvcHtmlString(String.Format("{0}{1}", labelBuilder, inputBuilder));
}
此方法正常工作,直到expression.ReturnType.IsContainerObject()== true。 DisplayChildFieldsetsFor方法将从表达式的ReturnType中获取所有适当的属性,并递归调用RenderFieldsetDisplayFor方法。我想要做的是将父类型的属性提供给displayDelegate表达式。问题是,TValue的类型将根据父类型最初构建的每个属性进行更改。
那么,表达大师,你推荐什么?我是否需要创建一个访问者来更改lambda参数?或者,表达式参数是问题。我是Expression API的新手,我认为我不了解泛型,不知道我哪里出错了。