views:

3709

answers:

2

C# .NET 3.5. I'm trying to understand the intrinsic limitation of the C# Action object. Within the lamda (are those, in fact, lamdas?), we can perform assignments, call functions, even execute a ternary operation, but we can't execute a multi-statement operation.

Is this because the single-statement execution is just syntactic sugar for wrapping it in a delegate? Why does the first example below not work?

public class MyClass
{
    private int m_Count = 0;

    public void Test()
    {
        int value = 0;

        // Does not work, throws compile error
        Action action = () => { if(m_Count < 10) m_Count++; value = m_Count; }

        // Works
        Action action2 = () => value = delegate(){ 
            if(m_Count < 10) 
                m_Count++; 

            return m_Count;
        };

        // Works
        Action action3 = () => value = m_Count;

        // Works
        Action action4 = () => value = m_Count < 10 ? m_Count++ : 0;

        // Works
        Action action5 = () => value = Increment();
    }

    public int Increment()
    {
        if (m_Count < 10)
            m_Count++;

        return m_Count;
    }
}

EDIT: Grr, sorry for the noise. Originally, I had

Action action = () => if(m_Count < 10) m_Count++; value = m_Count;

Which threw a compile error, but then right before the post I thought I'd try wrapping it in braces

Action action = () => { if(m_Count < 10) m_Count++; value = m_Count; }

Which also threw a compile error, so I jumped to conclusions that it was the same problem. It works, though, if I toss in a semi-colon after the braces

Action action = () => { if(m_Count < 10) m_Count++; value = m_Count; };

Sorry for the noise!

EDIT 2: Thanks cfeduke, you posted that at the same time as my edit above - went ahead and marked as answer.

+5  A: 

You are missing a semi-colon, it compiles:

 Action action = () => { if (m_Count < 10) m_Count++; value = m_Count; };

When you say type name = statement; you need a semicolon even if you use braces for a code block.

cfeduke
+2  A: 

cfeduke has posted the solution to getting your code to compile.

Note that you can't convert statement-block lambda expressions into expression trees, even though you can convert them into delegates. There are other limitations on what you can convert into expression trees.

Going back to delegates, there are some limitations there - you can't write an iterator block within a lambda expression, for example. (I've wanted to do that before now - it gets weird when you try to get your head round it. You can't do it though.) For the most part, you can do almost anything you can do in a method.

Jon Skeet