views:

163

answers:

1

I am really struggling to understand why, when I change my code to use a lamdba expression, it doesn't work.

This code works and prints on console:

object dummy = new object();
InterServer.ExecuteDataReader(new InterServerRequest(ServerID.a_01, "dbo.getbooks") 
    { 
        Params = new Dictionary<string, object> { 
            { "Tool", "d1" }, 
            { "Loc", locale == string.Empty ? null : locale } } 
    },
    (_, reader) =>
        {
            reader.AsEnumerable(r => (r.GetString(r.GetOrdinal("book")))).ToList().ForEach(Console.WriteLine);
            return new Response(dummy);
        }
    );

This code has been changed to use a lambda expression; it doesn't print anything, I don't understand why:

InterServer.ExecuteDataReader(new InterServerRequest(ServerID.a_01, "dbo.getbooks")
    { 
        Params = new Dictionary<string, object> { 
            { "Tool", "d1" }, 
            { "Loc", locale == string.Empty ? null : locale } } 
    },
    (_, reader) =>
        {
            return new Response(new Action(() => 
                reader.AsEnumerable(r =>(r.GetString(r.GetOrdinal("book")))).ToList().ForEach(Console.WriteLine)));
        }
    );

This is really driving me mad as I don't see if I am doing anything wrong. Can someone help?

Thanks, AG

+5  A: 

What are you trying to achieve by making it use a lambda expression?

In this example, the Action is not invoked, therefore nothing happens. When the Action will be invoked you'll see the output.

The Action is not executed implicitly.

For example:

public void Call()
{
    // Call with int argument 1
    DoSomething(1);

    // Call with Func that returns 1
    // It'll never produce the value unless Func is invoked
    DoSomething(new Func<int>(() => 1));

    // Call with Func explicitly invoked
    // In this case the body of the lambda will be executed
    DoSomething(new Func<int>(() => 1).Invoke());
}

public void DoSomething(object obj)
{

}

Calling the Response constructor with Action will actually send the Action. If Response has an overload that invokes it and uses the return value, then the Action will appear only when the Response actually uses it (not necessary during the constructor call).

In your example, the work will be done anyway during the call to (_, reader) => ... so there is no work done "too early".

To make it clear (last sample I add :) ):

public void Call()
{
    DoSomething(new Action(() => Console.WriteLine("Arrived")));
}

public void DoSomething(Action obj)
{
    int x = 0; // Nothing printed yet
    Action storedAction = obj; // Nothing printed yet
    storedAction.Invoke(); // Message will be printed
}

Unless Response expects an Action it'll never get to execute its body.

Elisha
So what i am trying is my (_,reader) delegate return a Response(object obj). Hope thats fine. So in my 2nd example me rather evaluating something first and then returning a result wrapped in Response i am trying to do that work inside Response by calling Action delegate and returning Response as a result.so something like (_,reader) => new Response(new Action(() => domy workas i dont need to return anything ).Hope this helps you to let me know what am i doign wrong.
netmatrix01
Many thanks Elisha, Got it Now i can do something like this and it works new Response( new Action(() => reader.AsEnumerable(r => ( r.GetString(r.GetOrdinal("main_book")) )).ToList().ForEach(Console.WriteLine)).DynamicInvoke(null))
netmatrix01
Cool, but now it'll behave similar to the original implementation. The Invoke executes it immediately, meaning in both cases it will run just before Response it created.
Elisha