1

私は変えようとしています

@{Html.RenderAction("Foo", "TheAction");}

@{Html.RenderAction((FooController c) => c.TheAction );}

これは多くの点で優れていますが、改善されます。

  • F12-ナビゲーション
  • タイプ使用状況の検出(リシャーパーなど)
  • メソッド使用状況の検出
  • 厳格さ
  • ...デッドリンクをプロジェクトから遠ざける可能性

...だから私はこのような拡張クラスを書きました:

using System;
using System.Linq.Expressions;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Web.Mvc;
using System.Web.Mvc.Html;

namespace V3NET.MVC.Extensions
{
    public static class HtmlHelperExtension
    {
        public static void RenderAction<T>
            (this HtmlHelper helper, Expression<Func<T, Func<int, int?, ActionResult>>> action)
        {
            var actionName =
                (
                    (MethodInfo)
                    (
                        (ConstantExpression)
                        (
                            (MethodCallExpression)
                            (
                                ((UnaryExpression)action.Body).Operand
                            )
                        ).Object
                    ).Value
               ).Name;

            var controllerType = action.Parameters[0].Type;
            var controllerName = new Regex("Controller$").Replace(controllerType.Name, "");

            helper.RenderAction(actionName, controllerName);
        }
    }
}

...しかし、ご覧のとおり、int、intを実行するアクションに固有の記述を行う必要がありますか?引数として。

これをより一般的に表現するには、無数のオーバーロードを記述する必要がないようにするにはどうすればよいですか?

4

1 に答える 1

2

を使用できますExpression<Action<TController>>

これは、あなたが書き込もうとしているヘルパーの改良版です。これは、たとえば非同期コントローラーアクションなど、ヘルパーがサポートしていないさらに多くのシナリオを考慮に入れています。また、引数のタイプがコントローラーになるための一般的な制約を追加します。

public static class HtmlHelperExtension
{
    public static void RenderAction<TController>(
        this HtmlHelper helper, 
        Expression<Action<TController>> action,
        object routeValues
    ) where TController: Controller
    {
        var body = action.Body as MethodCallExpression;
        if (body == null)
        {
            throw new ArgumentException("Must be a method call", "action");
        }

        var controllerName = typeof(TController).Name;
        if (!controllerName.EndsWith("Controller", StringComparison.OrdinalIgnoreCase))
        {
            throw new ArgumentException("Target must end in Controller", "action");
        }
        controllerName = controllerName.Substring(0, controllerName.Length - "Controller".Length);
        if (controllerName.Length == 0)
        {
            throw new ArgumentException("Cannot route to controller", "action");
        }

        var actionName = GetTargetActionName(body.Method);
        helper.RenderAction(actionName, controllerName, routeValues);
    }

    private static string GetTargetActionName(MethodInfo methodInfo)
    {
        string name = methodInfo.Name;
        if (methodInfo.IsDefined(typeof(NonActionAttribute), true))
        {
            throw new InvalidOperationException(
                string.Format(
                    CultureInfo.CurrentCulture, 
                    "Cannot call non action {0}", 
                    name
                )
            );
        }
        var attribute = methodInfo.GetCustomAttributes(typeof(ActionNameAttribute), true).OfType<ActionNameAttribute>().FirstOrDefault<ActionNameAttribute>();
        if (attribute != null)
        {
            return attribute.Name;
        }
        if (methodInfo.DeclaringType.IsSubclassOf(typeof(AsyncController)))
        {
            if (name.EndsWith("Async", StringComparison.OrdinalIgnoreCase))
            {
                return name.Substring(0, name.Length - "Async".Length);
            }
            if (name.EndsWith("Completed", StringComparison.OrdinalIgnoreCase))
            {
                throw new InvalidOperationException(
                    string.Format(
                        CultureInfo.CurrentCulture, 
                        "Cannot call {0}Completed method", 
                        name
                    )
                );
            }
        }
        return name;
    }
}
于 2012-10-09T09:44:53.780 に答える