Expression trees - different compiler behaviour fo

2019-07-13 08:17发布

问题:

Given a simple piece of code which can return the name of a property in VB.NET:

Function NameForProperty(Of T)(ByVal field As Expression(Of Action(Of T))) As String

    Dim expression = DirectCast(field.Body, MemberExpression)

    Return expression.Member.Name

End Function

Which works like this:

NameForProperty(Of String)(Function (s) s.Length) ' ==> returns "Length"

And what I thought would have been the equivalent in C#:

string NameForProperty<T>(Expression<Action<T>> field)
{
    var expression = (MemberExpression)field.Body;

    return expression.Member.Name;
}

When I try to call the C# version:

NameForProperty<string>(s=>s.Length);

It returns a compiler error:

Only assignment, call, increment, decrement, and new object expressions can be used as a statement

My question is: what is the difference between the two pieces of code?

EDIT

Ivan has provided an answer as to why the code does not work in C#. I am still curious as to why it does work in VB.NET.

EDIT#2

To be clear, I'm not looking for code which works -- simply why the code would work in VB.NET and not C#.

回答1:

public static class TypeMember<TClass>
{
    public static string PropertyName<TProp>(Expression<Func<TClass, TProp>> expression)
    {
        var body = expression.Body as MemberExpression;

        if (body == null)
            throw new ArgumentException("'expression' should be a property expression");

        return body.Member.Name;
    }
}

var propName = TypeMember<string>.PropertyName(s => s.Length);

The problem with your version lies in the fact that you're trying to use Action<T>. It returns nothing and thus lambda's body (s.Length) should be a statement. And it is not a statement actually. So compiler complains about it.

It would complain in the same way if you'd wrote

public void A()
{
    string s = "abc";
    s.Length;
}

It is the same thing.

I'm not an expert in VB.NET though, so I can't explain why it is working in VB, sorry.



回答2:

I would try changing the method to Func instead of Action.

Your statement is not valid as the error says. If you change the Action to Func it's ok, because Length is the return value. Maybe the VB compiler has other checks / requirements.