0

我目前正在尝试创建一个 HtmlHelper,它采用与内置帮助器 LabelFor<>、DisplayFor<>、EditorFor<> 等相同的表达式,但专门针对枚举类型:

例如model => model.MyEnumProperty

我是整个 lambda 表达式的新手,尽管到目前为止我做的或多或少都还不错(在 SackOverflow 社区的其他答案的帮助下),我现在在尝试检索对象时遇到以下异常(即,model)在表达式中:

“从范围''引用'WCSFAMembershipDatabase.Models.Address'类型的变量'模型',但未定义”

public static MvcHtmlString EnumDisplayFor<TModel, TEnum>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TEnum>> expression)
{
    // memberExp represents "model.MyEnumProperty"
    MemberExpression memberExp = (MemberExpression)expression.Body;
    if (memberExp == null)
    {
        throw new ArgumentException(string.Format(
            "Expression '{0}' refers to a method, not a property.",
            expression.ToString()));
    }

    // modelExp represents "model"
    Expression modelExp = memberExp.Expression;

    // Convert modelExp to a Lambda Expression that can be compiled into a delegate that returns a 'model' object
    Expression<Func<TModel>> modelLambda = Expression.Lambda<Func<TModel>>(modelExp);

    // Compile modelLambda into the delegate
    // The next line is where the exception occurs...
    Func<TModel> modelDel = modelLambda.Compile();

    // Retrieve the 'model' object
    TModel modelVal = modelDel();

    // Compile the original expression into a delegate that accepts a 'model' object and returns the value of 'MyEnumProperty'
    Func<TModel, TEnum> valueDel = expression.Compile();

    // Retrieve 'MyEnumProperty' value
    TEnum value = valueDel(modelVal);

    // return the description or string value of 'MyEnumProperty'
    return MvcHtmlString.Create(GetEnumDescription(value));
}

// Function returns the Description Attribute (if one exists) or the string 
// representation for the specified enum value.
private static string GetEnumDescription<TEnum>(TEnum value)
{
    FieldInfo fi = value.GetType().GetField(value.ToString());

    DescriptionAttribute[] attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);

    if ((attributes != null) && (attributes.Length > 0))
        return attributes[0].Description;
    else
        return value.ToString();
}

EnumDisplayFor中与表达式相关的代码是根据以下位置的详细信息拼凑而成的:

我确实找到了一些其他问题,它们提到了与 lambda 表达式相关的相同异常,但它们都处于有人手动制作表达式树的上下文中,我无法弄清楚答案中的信息如何适用于我的案例.

如果有人能解释(a)为什么会发生异常以及(b)我如何解决它,我将不胜感激。:-)

提前致谢。

4

2 回答 2

1

你试图做的事情没有意义。您正在尝试仅基于 lambda 表达式(据我所知)查找模型对象。

更具体地说,忽略事物的枚举方面,如果我给您一个Expression<string, int>构造 from text => text.Length,则没有特定的字符串可以引用-但是您的代码将尝试Func<string>从该 lambda 表达式构建和运行 a 。那根本行不通。

基本上,您需要一个模型对象来应用您提供的投影。我不知道您想从哪里获取该模型对象(也许HtmlHelper是您当前忽略的参数?),但您不能只从投影中获取它。

于 2012-08-01T06:15:53.867 回答
0

正如乔恩所说,试图从表达式中提取模型参数是行不通的,因为表达式根本没有那个参数

当您创建 lambda model => model.Property 时,您只是在说您希望方法体如何。该 lambda 编译为一个委托 Func,或者换句话说,一个需要一个参数并返回一个值的方法

因此,为了调用 Func ,您需要传递一个参数,在本例中为模型参数。

在您的示例中,您的方法需要在调用“表达式”以获取返回值之前从某处获取模型。您可以从 HtmlHelper 参数中获取当前模型,如下所示:

public static MvcHtmlString EnumDisplayFor<TModel, TEnum>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TEnum>> expression)
    {
        //Get the model
        TModel model = htmlHelper.ViewData.Model;

        //Compile expression as Func
        Func<TModel, TEnum> method = expression.Compile();

        //Calling compiled expression return TEnum
        TEnum enumValue = method(model);

        return MvcHtmlString.Create(GetEnumDescription(enumValue));
    }
于 2012-08-01T07:37:46.807 回答