【问题标题】:Convert Expression<Func<T, bool?>> to Expression<Func<T, bool>>将 Expression<Func<T, bool?>> 转换为 Expression<Func<T, bool>>
【发布时间】:2013-01-16 10:48:35
【问题描述】:

很简单的问题。

我有一个 MVC 视图,它显示一个 Nullable Bool,例如,

Html.CheckBoxFor(model=>model.NullableBoolHere, Model.NullableBoolHere, 

我想创建一个新的 html 帮助器,它将接受这种类型,然后转换

Null || False => False
True => True

所以我有以下

public static MvcHtmlString CheckBoxFor<TModel>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, bool?>> expression, object htmlAttributes, bool disabled)
    {
        IDictionary<string, object> values = new RouteValueDictionary(htmlAttributes);

        if (disabled)
            values.Add("disabled", "true");

        Expression<Func<TModel, bool>> boolExpression = CONVERT_TO_BOOL_HERE(expression);


        return htmlHelper.CheckBoxFor(expression, values);
    }

感谢任何帮助,我知道我将不得不使用递归来复制表达式,但只是不确定如何导航表达式本身,找到 bool?,转换为 bool。

【问题讨论】:

    标签: asp.net-mvc linq lambda expression


    【解决方案1】:

    您可以使用此代码:

    var body = Expression.Coalesce(expression.Body, Expression.Constant(false));
    var boolExpression = (Expression<Func<TModel, bool>>)
        Expression.Lambda(body, expression.Parameters.First());
    

    其他答案的优点是它不编译第一个表达式,它只是包装它。生成的表达式类似于以下代码创建的表达式:

    m => m.NullableBoolHere ?? false
    

    Check it live.

    【讨论】:

    • 我喜欢你在这里所做的,有道理。似乎在此之后我遇到了一个 MVC 问题,我收到错误“模板只能用于字段访问、属性访问、单维数组索引或单参数自定义索引器表达式。”但我会玩这个,看看会发生什么。谢谢
    • @adudley:在这种情况下,MVC 引擎会限制它允许的表达式,因为它实际上不会执行它们,而是解析它们并根据解析的表达式树生成一些代码。为了保持解析逻辑相对简单,它对表达式中实际允许的内容施加了严格的限制。你最好在你的模型中创建一个包含NullableBoolHere的属性。
    【解决方案2】:

    所以,最后,我能找到的唯一方法就是解决布尔问题?自己变成一个布尔值,然后通过传入正确的名称等返回一个“正常”复选框。

    不过,这确实是一种享受,所以一切都很好。如果您确实知道获得正确 ParameterName 的更好方法,那将是很高兴听到。

    public static MvcHtmlString CheckBoxFor<TModel>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, bool?>> expression, object htmlAttributes, bool disabled)
        {
            IDictionary<string, object> values = new RouteValueDictionary(htmlAttributes);
    
            if (disabled)
                values.Add("disabled", "true");
    
            //Compile the expression to get the value from it.
            var compiled = expression.Compile().Invoke(htmlHelper.ViewData.Model);
            bool checkValue = compiled.HasValue ? compiled.Value : false; //evaluate the compiled expression
    
            //Get the name of the id we should use
            //var parameterName = ((MemberExpression)expression.Body).Member.Name; // only gives the last part
            string parameterName = expression.Body.ToString().Replace("model.", "");//.Replace(".", HtmlHelper.IdAttributeDotReplacement);
    
            //Return our 'hand made' checkbox
            return htmlHelper.CheckBox(parameterName, checkValue, values);
        }
    

    【讨论】:

    • 还有可能的语法:var b= e.Compile()(htmlHelper.ViewData.Model);无需使用 Invoke
    【解决方案3】:

    我想仅仅将表达式转换为另一种类型是不够的,MVC 使用表达式是有原因的,所以我怀疑它需要检查给定的表达式并对其应用一些魔法。

    您可以创建一个执行转换的新表达式,如下所示:

     Expression<Func<TModel, bool>> boolExpression = 
            T => expression.Compile()(T).GetValueOrDefault(false);
    

    但正如我所说,我怀疑这还不够,MVC 可能想要检查表达式中的模型成员等。

    【讨论】:

    • 是的,我收到了一个错误,正如预期的那样。 MVC 需要“读取”未编译​​的表达式来做“魔术”! “模板只能与字段访问、属性访问、单维数组索引或单参数自定义索引器表达式一起使用。”
    【解决方案4】:

    这个怎么样:

     Expression<Func<TModel, bool>> boolExpression = model =>
            {
                 bool? result = expression.Compile()(model);
    
                 return result.HasValue ? result.Value : false;
            };
    

    这样你包装了原始表达式,你可以从 bool 转换结果?布尔值。

    它能解决你的问题吗?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-31
      • 2012-04-05
      • 2021-06-17
      相关资源
      最近更新 更多