5

I'm trying to use a Lambda expression and reflection to get a member hierarchical name (rather than using a text constant), to enforce compile-time errors if my control binding information is invalid.

This is in an ASP.NET MVC project, but it's not an MVC-specific question AFAIK. EDIT: Specifically, I want the following to evaluate to true:

string fullname = GetExpressionText(model => model.Locations.PreferredAreas);
"Locations.PreferredAreas" == fullname;

Instead I get a compile error:

Error 4: Cannot convert lambda expression to type 'System.Linq.Expressions.LambdaExpression' because it is not a delegate type.

Why does the parameter work in the second case below, but not the first?

// This doesn't compile:
string tb1 = System.Web.Mvc.ExpressionHelper.
    GetExpressionText(model => model.Locations.PreferredAreas);

// But this does:
MvcHtmlString tb2 =
    Html.TextBoxFor(model => model.Locations.PreferredAreas);

Here's the relevant code from the ASP.NET MVC Codeplex project. It looks to me like it passes the same parameter through to the same method:

// MVC extension method
public static MvcHtmlString TextBoxFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, IDictionary<string, object> htmlAttributes) {
    ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
    return TextBoxHelper(
        htmlHelper,
        metadata,
        metadata.Model,
        ExpressionHelper.GetExpressionText(expression),
        htmlAttributes);
}

// MVC utility method
public static string GetExpressionText(LambdaExpression expression) {
    // Split apart the expression string for property/field accessors to create its name
    // etc...
5
  • You forgot to include the most relevant part your problem — GetExpressionText source code :) Commented Mar 15, 2011 at 6:11
  • Never mind, it's an MVC helper. See my answer. Commented Mar 15, 2011 at 6:24
  • is that actually relevant? based on Eric Lippert's answer (the content of his answer, not merely the fact that he was able to answer) the source behind the GetExpressionText isn't relevant, right? Commented Mar 15, 2011 at 6:26
  • Do you remember what you ultimately ended up doing? Where was that delegate Eric was talking about? Commented Jun 3, 2015 at 15:30
  • See the other answer below for a code sample, Lum. Commented Jun 3, 2015 at 15:43

3 Answers 3

15

The error message is correct. A lambda can be converted to a compatible delegate type, D, or to an expression-of-compatible-delegate-type Expression<D>. Expression<Func<TM, TP>> is one of those. "LambdaExpression" is neither of those. Therefore you get an error trying to convert the lambda to LambdaExpression, but not to an actual expression tree type. There has to be a delegate in there somewhere.

Sign up to request clarification or add additional context in comments.

6 Comments

Thank you Eric, I'm sure you are right. I am trying to understand it :)
so you are saying (lambda to Expression<D> to LambaExpression) is valid and is what is occurring, but (lambda to LambdaExpression) is not?
@shannon: Correct. LambdaExpression is the base class of Expression<D>. The lambda needs to know what the delegate type is. All you're telling it is "this lambda expression should be treated as a lambda expression" That doesn't give the compiler anything to go on. You need to say "this lambda expression should be treated as an expression tree for an expression that takes an int and returns a string" or whatever. There needs to be a delegate type in there somewhere.
yeah, that's where I'm confused, though, because TM and TP are both inferred anyway, so the compiler already knows the lamba is an expression that takes a TM and returns a TP. I'm sure I'll work it through, though :)
@shannon: From what is TM inferred? (The call site and the extension method you posted do not appear to match.) When you work it out, you'll discover that TM is not inferred from the lambda; the lambda does not have enough information in it to determine what the type of "model" has to be; that information has to come from somewhere and in the LambdaExpression case you're not giving that information to the compiler anywhere.
|
3

Before trying to fix the lambda expressions, be sure that the following references have already been added:

System.Linq;
System.Linq.Expressions;

The lack of these references may cause the same error as well ("Cannot convert lambda expression to type 'System.Linq.Expressions.Lambda Expression' because it is not a delegate type").

Comments

2

I think you should try to use a helper method like that:

public static string GetExpressionText<M, P>(this M model, Expression<Func<M, P>> ex)
{
    return GetExpressionText(ex);
}

3 Comments

it seems that this would work, but the instance of M isn't required, and so this doesn't actually belong in the extension methods, right?
Exactly, you can declare this helper as GetExpressionText<M, P>(Expression<Func<M, P>> ex), but in that case you'll have to specify type parameters explicitly. Extension method syntax is more terse, although it requires to declare an 'unused' parameter.
Sorry I can't assign the answer in two places - Eric fixed my brain, you gave me the code I needed... it was a toss-up, but I figure Eric answered the letter of my question and tried (nearly successfully) to teach a man to fish, in the process.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.