Alex Bloom
Alex Bloom

Reputation: 83

C# string function not returning a value

I'm having an issue with this function.

public static string artnetReceiver()
{
    string dataout;
    List<string> dmxString = new List<string>();
    byte[] _dmxData = new byte[511];

    artnet.NewPacket += (object sender, ArtNet.Sockets.NewPacketEventArgs<ArtNet.Packets.ArtNetPacket> e) =>
    {
        if (e.Packet.OpCode == ArtNet.Enums.ArtNetOpCodes.Dmx)
        {
            var packet = e.Packet as ArtNet.Packets.ArtNetDmxPacket;
            Console.Clear();

            if (packet.DmxData != _dmxData)
            {
                for (var i = 0; i < packet.DmxData.Length; i++)
                {
                    if (packet.DmxData[i] != 0)
                    {
                    }

                    int temp = i + 1;
                    string chanNum = temp.ToString();
                    string chanValue = packet.DmxData[i].ToString();

                    dmxString.Add(chanNum + "-" + chanValue);
                };

                //dmx stuff

                dataout = string.Join(",", dmxString.ToArray());
                dmxOut = dataout;
                //Console.WriteLine(dataout);//works here

                _dmxData = packet.DmxData;
            }
        }
    };
    return dataout; // doesn't work
}

For whatever reason the string i build won't get to the return portion however when I use Console.WriteLine(dataout); further up in the function it spits out to console but if i call it thru the function else where like for example, Console.WriteLine(artnetReceiver()); I get a blank result. EDIT new code

public static void artnetReceiver()
        {  
               artnet.NewPacket += OnArtNet_NewPacket;  
        }

       public static string ProcessDataOut(string dataout)
       {
            return dataout;
       }

        /*public static void getDMXPackets()
        {
            artnetReceiver((val) =>
            {
                return val;
            });

        }*/

        public static void OnArtNet_NewPacket(object sender, ArtNet.Sockets.NewPacketEventArgs<ArtNet.Packets.ArtNetPacket> e)
        {
            byte[] _dmxData = new byte[511];
            List<string> dmxString = new List<string>();
            string dataout; //included here so the sample will compile
            if (e.Packet.OpCode == ArtNet.Enums.ArtNetOpCodes.Dmx)
            {
                var packet = e.Packet as ArtNet.Packets.ArtNetDmxPacket;
                Console.Clear();

                if (packet.DmxData != _dmxData)
                {
                    for (var i = 0; i < packet.DmxData.Length; i++)
                    {
                        if (packet.DmxData[i] != 0)
                        {
                        }

                        int temp = i + 1;
                        string chanNum = temp.ToString();
                        string chanValue = packet.DmxData[i].ToString();

                        dmxString.Add(chanNum + "-" + chanValue);
                    };

                    //dmx stuff

                    dataout = string.Join(",", dmxString.ToArray());
                    dmxOut = dataout;
                    _dmxData = packet.DmxData;
                    ProcessDataOut(dataout);
                }
            }
        }


        byte[] _dmxData = new byte[511];

Okay the problem i'm struggling with now is actually later on in my code calling say for example artnetReceiver() and when it runs it returns the string value so i can export send it as a packet string like so mstrResponse = "Data: " + artnetReceiver();

Upvotes: 0

Views: 251

Answers (2)

Stephen Byrne
Stephen Byrne

Reputation: 7485

At the risk of having basically a duplicate answer to MichaC's one, here's my explanation for why you are observing this behaviour, with a possibly simpler solution.

This code

artnet.NewPacket += (object sender, ArtNet.Sockets.NewPacketEventArgs<ArtNet.Packets.ArtNetPacket> e) =>{
 //code omitted
}

is saying "When artnet raises the NewPacket event at some point in the future, execute the code between { and }."

So nothing actually happens when this code is encountered first except that the runtime remembers to come back when artnet.NewPacket occurs, and execute the code.

So with that in mind, when you execute artnetReceiver, the sequence of events is more or less this

  1. You declare dataout with no value.
  2. You tell the runtime to execute some code when artnet.NewPacket occurs sometime in the future. This code incidentally is in the form of an anonymous delegate, which is basically a self-contained void function that has no return value.
  3. You then return dataout, which is of course blank.
  4. Later, the artnet.NewPacket event occurs, and the delegate is executed, but crucially, when the last closing brace defining the delegate is encountered, the runtime jumps out of this delegate method, it does not continue on to step 3 again! That's because from the perspective of the runtime, the delegate isn't part of the function that defined it, so it's treated as a totally standalone method.

Perhaps this will make it clearer; let's move the event handler delegate into a separate method of its own, defined outside of artnetReceiver:

public static string artnetReceiver()
{
    string dataout;
    List<string> dmxString = new List<string>();
    byte[] _dmxData = new byte[511];
    artnet.NewPacket += OnArtNet_NewPacket;
    return dataout; // doesn't work
}

And the event handler is

//note the return type - it's void!
public void OnArtNet_NewPacket(object sender, ArtNet.Sockets.NewPacketEventArgs<ArtNet.Packets.ArtNetPacket> e)
{
string dataout; //included here so the sample will compile
if (e.Packet.OpCode == ArtNet.Enums.ArtNetOpCodes.Dmx)
        {
            var packet = e.Packet as ArtNet.Packets.ArtNetDmxPacket;
            Console.Clear();

            if (packet.DmxData != _dmxData)
            {
                for (var i = 0; i < packet.DmxData.Length; i++)
                {
                    if (packet.DmxData[i] != 0)
                    {
                    }

                    int temp = i + 1;
                    string chanNum = temp.ToString();
                    string chanValue = packet.DmxData[i].ToString();

                    dmxString.Add(chanNum + "-" + chanValue);
                };

                //dmx stuff

                dataout = string.Join(",", dmxString.ToArray());
                dmxOut = dataout;
                //Console.WriteLine(dataout);//works here

                _dmxData = packet.DmxData;
            }
        }
}

So as you can clearly see, nothing actually gets executed when you assign the event handler to the event, it's only when the even fires that the code is executed.

So in terms of the solution - whatever you need to do with dataout, must be initiated from inside the event handler. The simplest way to do this will be if you can encapsulate whatever the next step of your process is within a method contained in the same class as artnetReceiver - let's say you call it ProcessDataOut(string dataout). Then you simply modify the event handler so that the last thing it does it call that method, passing dataout:

_dmxData = packet.DmxData;
ProcessDataOut(dataout);
}

Note: The ProcessDataOut method can't have a return type (well, it can but it's pointless, since there is nothing there to receive the returned value). Therefore whatever you need to do with dataout, you need to do it inside the ProcessDataOut method. This is just how asynchronous/event-driven code works :)

However the more elegant (and more flexible) solution is to use a callback delegate (Action or Func) as indicated in MichaC's answer, but the same concept applies; this delegate can't return anything and has to do the "next step" of whatever process you are trying to implement.

The implications of this are that you may very well need to invert your application logic; that is to say that rather than having something waiting on the "outside" for artnetReceiver to return something (which it never will) you need to move that something inside artnetReceiver's ProcessDataOut method.

Upvotes: 1

MichaC
MichaC

Reputation: 13380

That's an event handler you have there in your method, this runs asynchronously to your method invocation. You cannot expect to return a variable set within the event handle.

Store the value somewhere else in a global scope, or use for example a callback Action to return you the value

Example usage of Action<T>

public static void AnotherFunction()
{
    ArtnetReceiver((val) =>
    {
        // do work with the value returned
    });
}

public static void ArtnetReceiver(Action<string> callback)
{
    artnet.NewPacket += (object sender, ArtNet.Sockets.NewPacketEventArgs<ArtNet.Packets.ArtNetPacket> e) =>
    {
        // some stuff going on...

        var dataout = value;
        callback(dataout);
    };
}

Upvotes: 3

Related Questions