2

編集: 簡略化された質問の実際のバージョンは以下にありますが、おそらくこの質問に答える必要はありません。

再利用したい MethodCallExpression があります。式呼び出しの本体で参照されているメソッドは正しいメソッドですが、型引数の 1 つが変更されています。既存の MethodCallExpression が与えられた場合、本体の式は同じだが型引数が異なる新しい MethodCallExpression を構築したいと考えています。これは可能ですか?どうすればこれを達成できますか?ありがとう。

REAL WORLD QUESTION FOLLOWS (より具体的な例が必要でない限り、これは無視してください):

表示テンプレートとして使用される式Expression<Func<HtmlHelper<TModel>, Expression<Func<TModel, TValue>>, MvcHtmlString>>があります (HtmlHelper と Expression> を入力として取り、McvHtmlString を出力します)。TValue がカスタム クラス インスタンスの場合、そのプロパティは、オブジェクト自体ではなく、式デリゲートに渡す必要があります。これは、TValue が親オブジェクトから現在のプロパティの型に変更されることを意味するため、問題があります。(コードは続きます)

この問題を解決するにはどうすればよいか、正確にはわかりません。ExpressionVisitor を使用してこの種の式の変更を実現できることは理解していますが、式が冗長すぎる可能性があるという事実も考慮しています。助けてください。

私が作成しようとしているのは、ラベル/値フィールドのペアをレンダリングするための HtmlHelper 拡張メソッド (ASP.NET MVC) です。ただし、バインドされたフィールドとバインドされていないフィールドの概念があります。バインドされたフィールドは、いくつかのノックアウト属性で単純にレンダリングされます。C# Expression API を使用していくつかの再利用可能なコンポーネントをリファクタリングしようとするまで、これはうまく機能していました。

まず、フィールドセットをバインドされた要素またはバインドされていない要素としてレンダリングするために使用される 2 つのパブリック拡張メソッドを次に示します。

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 メソッドに渡される 2 つの異なる式に注意してください。これは基本的に、下位レベルのメソッドが値をレンダリングするために使用するデリゲートです。

    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 の型が、最初は親の型に基づいて構築されたため、プロパティごとに変更されることです。

では、表現の達人、あなたは何をお勧めしますか? ラムダ引数を変更するには、ビジターを作成する必要がありますか? または、式パラメータが問題ですか。私は Expression API に非常に慣れていないため、どこが間違っているかを知るのに十分なジェネリックを理解していないと思います。

4

0 に答える 0