0

I have something like this. How can i return value form anonymous method? returnRate = d;. For example let i have some class which get's messages from server. I want to process those messages in classes Cars and Bicycles is that clearly now?

namespace ConsoleApplication9
{
class Program
{
    static void Main(string[] args)
    {
        Cars c = new Cars();
        Bicycles b = new Bicycles();
    }
}
public class Cars
{
    public Cars()
    {
        GetData G1 = new GetData();
        Dictionary<string, string> D1 = new Dictionary<string, string>();
        G1.ProcessCars(ref D1);
    }
}
public class Bicycles
{
    public Bicycles()
    {
        GetData G2 = new GetData();
        Dictionary<string, string> D2 = new Dictionary<string, string>();
        G2.ProcessBicycles(ref D2);
    }
}
public class Singleton
{
    private static Singleton instance;

    public Dictionary<string, Action<MessageEventArgs>> Handle;
    private Singleton() 
    {
        Handle = new Dictionary<string, Action<MessageEventArgs>>();
    }

    public static Singleton Instance
    {
        get
        {
            if (instance == null)
            {
                instance = new Singleton();
            }
            return instance;
        }
    }
}
public class GetData
{
    private Client socket;
    public GetData()
    {
        socket = new Client("http://echo.jsontest.com/bicycles/10");
        socket.Message += Message;
    }
    public void ProcessBicycles(ref Dictionary<string, string> returnRate)
    {
        Singleton.Instance.Handle.Add("bicycles", (m) => 
        {
            Dictionary<string, string> d = m.Message.Json.GetFirstArgAs<Dictionary<string, string>>() as Dictionary<string, string>;
            //returnRate = d;
        });
    }
    public void ProcessCars(ref Dictionary<string, string> returnRate)
    {
        Singleton.Instance.Handle.Add("cars", (m) =>
        {
            Dictionary<string, string> d = m.Message.Json.GetFirstArgAs<Dictionary<string, string>>() as Dictionary<string, string>;
            //returnRate = d;
        });
    }
    private void Message(object sender, MessageEventArgs e)
    {
        if (Singleton.Instance.Handle.ContainsKey(e.Message.Event))
        {
            Singleton.Instance.Handle[e.Message.Event](e);
        }

    }
}
}
A191919
  • 3,422
  • 7
  • 49
  • 93
  • 1
    so what you want to do here is achieve a closure around an input by ref variable, and add that to your dictornary? If so, can you create a simplified, concise question that asks exactly that? In fact, it even seems the dictionary is an unnecessary distraction here... – Amit Aug 27 '15 at 14:07
  • And after you do change your question, see [this](http://stackoverflow.com/questions/1365689/cannot-use-ref-or-out-parameter-in-lambda-expressions) potential duplicate – Amit Aug 27 '15 at 14:28
  • is it better now? Or i should try to make question more clearly. – A191919 Aug 27 '15 at 14:58
  • You should tell us exactly **why** you need to pass the `Dictionary` as a `ref` parameter, or if you are open to other solutions. Also, your question should always include a [Minimal, Complete and Verifiable Example](http://stackoverflow.com/help/mcve), as well as a description of your input and expected output parameters. – Henrik Ilgen Aug 27 '15 at 15:21
  • I edited question in third time. What wrong now? – A191919 Aug 28 '15 at 12:09

4 Answers4

1

You'll have to pass in the Action yourself, rather than creating it with a ref parameter. So your Add method simply becomes:

public void Add(Action<string> action) {
    Handle.Add("1", action);
}

You can call it like this:

Add(m => ReturnRate = m);

This is a kind of Callback function, which can be used for a kind of asynchronous programming. However, it might be worth your time to read about async and await. If you could give us more information about what your scenario exactly is, we might be able to give you more hints.

If you have to use a ref parameter (for some strange reason), I think you're out of luck...

Henrik Ilgen
  • 1,879
  • 1
  • 17
  • 35
0

This is because the used variables that are used in the the anonymous method body but are outside of it, will be public fields in the generated class made by the compiler. But you can introduce a local variable to make it compilable:

public void Add(ref string rate)
{
    string r = rate;
    Handle.Add("1", (m) => 
    { 
        Console.WriteLine(m);
        r = m;
    });

    rate = r;
}

And the compiler will generate this in the background:

public void Add(ref string rate)
{
    <>c__DisplayClass1 CS$<>8__locals2 = new <>c__DisplayClass1();
    CS$<>8__locals2.r = rate;
    this.Handle.Add("1", new Action<string>(CS$<>8__locals2.<Add>b__0));
    rate = CS$<>8__locals2.r;
}

[CompilerGenerated]
private sealed class <>c__DisplayClass1
{
    public string r;

    public void <Add>b__0(string m)
    {
        Console.WriteLine(m);
        this.r = m;
    }
}

Note: Though this can be compiled, it will not work as you expect, because calling the outer Add will not execute the delegate added by Handle.Add. To return the m from the inner delegate you must use a Func instead.

György Kőszeg
  • 17,093
  • 6
  • 37
  • 65
  • 2
    That will change Rate during the Add call not during the actual anonumous method call – Juan Aug 27 '15 at 12:51
  • @Juan - I know, and I added the Note part to make it clear. So you can reset your downvote now. – György Kőszeg Aug 27 '15 at 13:08
  • 1
    @taffer The fact that you admit in your answer that this won't actually work doesn't mean he should remove his downvote. The fact that you're admitting that the code won't work means that the people who have upvoted should remove their upvote. – Servy Aug 27 '15 at 13:16
0

You should use Func<string,string> instead Action

Action<string> means void function(string s) Func<string,string> means string function(string s)

However it depends on usage you want to achieve.

Ric
  • 12,855
  • 3
  • 30
  • 36
roxik0
  • 97
  • 6
-1

You should use Func<string,string> (delegate Func<in T,out TResult>) which is equivalent to some function that takes in string and returns string

for eg:-

private string MyFunction(string inputstring){}

Whereas Action<string> (delegate Action<in T>) corresponds to a function which only takes input and returns nothing

    private void MyFunction(string inputstring){}

You can modify your code to something like

    private Dictionary<string, Func<string,string>> Handle;

    private string ReturnRate;
    public data()
    {
        Handle = new Dictionary<string, Func<string,string>>();

        Add(ref ReturnRate);

        Handle["1"]("MyValue");


        Console.WriteLine(ReturnRate);
    }
    public void Add(ref string rate)
    {
      string somevalue=rate;
        Handle.Add("1", (m) =>
        {
             Console.WriteLine(m);
            somevalue= m;
            return m;
        });


    }
Rohit
  • 10,056
  • 7
  • 50
  • 82
  • You're suggesting making the method return a value, then ignoring that returned value, as well as having the method modify a variable that it won't make sense to modify in all situations, and that will be shared between all of the delegates in this dictionary, resulting in them "fighting" with each other over this variable. – Servy Aug 27 '15 at 13:15
  • Servy what you recommend to do? – A191919 Aug 27 '15 at 13:34
  • @A191919 The OP hasn't actually stated what the desired behavior of the application is, so there's no real way to tell them how to implement something they haven't described. – Servy Aug 27 '15 at 13:49