Convert Expression to Expression>

2019-04-12 16:16发布

Simple question really.

I have MVC view that displays a Nullable Bool, e,g,

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

and I want to create a new html helper, that will accept this type, and then convert

Null || False => False
True => True

so I have the following

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);
    }

Any help appreciated, I understand I will have to use recursion to copy the expression, but just not sure how to go about navigating the expression itself, find the bool?, convert to bool.

4条回答
一纸荒年 Trace。
2楼-- · 2019-04-12 16:23

You can use this code:

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

The advantage to the other answers is that it doesn't compile the first expression, it just wraps it. The resulting expression is similar to one created by this code:

m => m.NullableBoolHere ?? false

Check it live.

查看更多
姐就是有狂的资本
3楼-- · 2019-04-12 16:24

How about this:

 Expression<Func<TModel, bool>> boolExpression = model =>
        {
             bool? result = expression.Compile()(model);

             return result.HasValue ? result.Value : false;
        };

That way you wrap the original expression and you can convert the result from bool? to bool.

Does it solve your problem?

查看更多
Evening l夕情丶
4楼-- · 2019-04-12 16:29

So, in the end, the only way I could find to do it was to resolve the bool? into a bool myself, then return a 'normal' checkbox by passing in the correct name etc.

This does work a treat though, so all good. If you do know a better way of getting the correct ParameterName, it would be great to hear.

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);
    }
查看更多
狗以群分
5楼-- · 2019-04-12 16:35

I guess it won't be enough to just convert the expression to another type, MVC uses expressions for a reason so I suspect it needs to examine the given expression and apply some magic on it.

You can create a new expression that does the conversion, like this:

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

But as I said, I suspect it will not be enough, MVC probably wants to examine model members etc inside the expression.

查看更多
登录 后发表回答