Reputation: 83
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
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
dataout
with no value.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.dataout
, which is of course blank.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
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