4

任意の数のラムダ式を取ることができる独自の拡張メソッドを作成しようとしていますが、複数の式を追加するたびにチョークするようです。

メソッドは次のとおりです。

public static MvcHtmlString _RouteButton<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, string label, string controller, string action, params Expression<Func<TModel, TProperty>>[] parameters)
{
   var test = parameters;
   return MvcHtmlString.Empty;
}

これを正常に呼び出すマークアップは次のとおりです。

<%: Html._RouteButton("details", "Health", "SystemDetails", m=>m.Id)%>

エラーが発生するマークアップは次のとおりです。

<%: Html._RouteButton("details", "Health", "SystemDetails", m=>m.Id, m=>m.Status)%>

エラーは次のとおりです。

メソッドの型引数は、使用法から推測できません。型引数を明示的に指定してみてください

どんな助けでも大歓迎です。ありがとう!

4

4 に答える 4

8

単純化しましょう:

using System;
class P
{
    static void M<R>(params Func<R>[] p) {}
    static void N(int i, string s, decimal m)
    {
        M(()=>i, ()=>s); // fails
        M(()=>i, ()=>s.Length); // succeeds
        M(()=>i, ()=>m); // succeeds
    }
}

プログラムが失敗する理由は明らかですか?

私のプログラムでは、各呼び出しはRを推測しようとします。最初の呼び出しでは、Rはintとstringの両方であると推測されます。したがって、intとstringの両方の型がないため、推論は失敗します。2番目の例では、Rはintであると推測され、...再びintになります。intがすべての境界に一致するため、これは成功します。3番目の例では、Rはintとdecimalであると推論されます。これは、すべてのintを暗黙的にdecimalに変換できるため、成功します。したがって、decimalは適切な推論です。

IdとStatusは、おそらく互換性のないタイプのプロパティです。これを実行する場合は、推測されるタイプの1つが最適なタイプである必要があります。

C#は、「ああ、犬、猫、魚の境界を推測しているので、動物を意味していると思います」とは決して言わないことに注意してください。C#はむしろ、「犬、猫、魚のどれも明らかに最良の境界ではないので、あなたが何を意味するのかわかりません。明示的に指定してください」と言っています。

于 2013-02-14T17:43:21.887 に答える
4

Eric Lippert's answer は、問題が何であるかを説明しています。実際に解決する方法を追加します。プロパティのタイプを返すためにラムダを必要としない可能性が高く、式ツリーを取得してプロパティを調べたいだけです。したがって、できることは、型を から に変更Func<TModel, TProperty>する(および型パラメーターFunc<TModel, object>を削除する) ことです。TPropertyC# の通常の型はすべて暗黙的に に変換できるためobject、この変更によりコードは正常にコンパイルおよび実行されます。

于 2013-02-14T21:55:00.323 に答える
1

誰かが同様のことを試みた場合に備えて、サイトでこれを取得したかった.

このコードはルート フォームを作成します。これを行うには、プロパティの名前とそのが必要です。

public static void _RouteButton<TModel>(this HtmlHelper<TModel> htmlHelper, string text, string controller, string action, params Expression<Func<TModel, object>>[] parameters)
{
    using (htmlHelper.BeginRouteForm("Default", new { controller = controller, action = action }))
    {
        foreach (Expression<Func<TModel, object>> p in parameters)
        {
            MemberExpression me;
            switch (p.Body.NodeType)
            {
                case ExpressionType.Convert:
                case ExpressionType.ConvertChecked:
                    var ue = p.Body as UnaryExpression;
                    me = ((ue != null) ? ue.Operand : null) as MemberExpression;
                    break;
                default:
                    me = p.Body as MemberExpression;
                    break;
            }
            string name = me.Member.Name;
            string value = p.Compile()(htmlHelper.ViewData.Model).ToString();
            HttpContext.Current.Response.Write(htmlHelper.Hidden(name, value).ToHtmlString());
        }
        HttpContext.Current.Response.Write("<input type='submit' value='" + text + "' />");
    }
}
于 2013-02-15T14:46:20.567 に答える