1

I have a C# class that wraps a UDP socket to make receiving and processing network data easier.

Whenever data is received, an event is fired with the data passed as an argument:

public event Action<byte[]> DataReceived = delegate(byte[] data) { };

I receive the data and fire the event like so:

while (socket.IsBound)
{
    var buffer = new byte[MaximumDataLength];

    socket.Receive(buffer);

    DataReceived(buffer);
}

My understanding is that the same array instance is passed to each event handler.

  1. Could this cause issues later on if one of those handlers modifys the array before the other handlers get to process it?

  2. If so, what are some good ways to remedy this?

sdgfsdh
  • 33,689
  • 26
  • 132
  • 245

2 Answers2

0

If you have the option make it an IEnumerable<byte>, as in:

Action<IEnumerable<byte>> DataReceived = (d) => { ... }

Then you can call it with anything enumerable, but the delegates get it in an unmodifiable form.

(If that doesn't work for you there's always ReadOnlyCollection<T>)


Clarification:

Since arrays implement IEnumerable<> (since .net 2.0) you can pass the byte[] directly to the handler:

byte[] buffer = SomeReadFunction();
DataReceived(buffer);

If you want to make it explicit for people reading the code you can always cast:

DataReceived((IEnumerable<byte>)buffer);
theB
  • 6,450
  • 1
  • 28
  • 38
  • So my event firing code would look like `DataReceived(buffer.ToList().AsReadOnly());` ? – sdgfsdh Sep 04 '15 at 22:41
  • Ah yes, that makes sense. The key here is that `IEnumerable` exposes no modifiers. – sdgfsdh Sep 04 '15 at 22:51
  • 1
    You also get the benefit that you can change the internal storage without having to change the subscribers. Want to change it to a `Queue<>` or a `List<>`? No problem. You turn the buffer into an implementation detail instead of a contractual obligation. – theB Sep 04 '15 at 22:54
  • 1
    @Biscuits - There are a lot of cases where you want an object to be immutable. There's also the benefit that I mentioned in my comment above. And [Arrays considered somewhat harmful](http://blogs.msdn.com/b/ericlippert/archive/2008/09/22/arrays-considered-somewhat-harmful.aspx) – theB Sep 04 '15 at 23:31
  • @theB But I can break your "security" with a simple explicit cast. If you truly need it to be immutable, it can be done properly. – Biscuits Sep 04 '15 at 23:47
  • @Biscuits - I never said anything about security. It's to catch carelessness, not malice. – theB Sep 04 '15 at 23:51
  • @theB So how do I get the length? Or how do I read only the last byte at the end? My point is just that this problem is not worth the cost of solving it properly. And if you must, there are better ways of doing this without making copies. IEnumerable is a poor answer for retaining as much as Array has to offer. – Biscuits Sep 05 '15 at 00:02
  • @Biscuits - 1) the .Count() extension method. 2) .Last() 3) I have no idea what you mean by `My point is just that this problem is not worth the cost of solving it properly.` – theB Sep 05 '15 at 00:11
  • @theB 1) that is slow (and feels silly). 2) that is also slow (and also feels silly) 3) this is just a personal opinion – Biscuits Sep 05 '15 at 00:24
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/88850/discussion-between-biscuits-and-theb). – Biscuits Sep 05 '15 at 00:26
0

Method 1

Use the Array.AsReadOnly<T> extension method to create a ReadOnlyCollection<T> in an efficient way.

https://msdn.microsoft.com/en-us/library/53kysx7b(v=vs.110).aspx

Method 2

You could implement a wrapper for ArraySegment<T> to make it read-only, as suggested in this answer.

https://stackoverflow.com/a/5757109/2707705

There are numerous benefits to using ArraySegment over lists or other collections.

what is the use of ArraySegment<T> class?

Notes

A typical idea could be to make copies of the byte array, but that might not work for you since every event handler would still be accessing the same copy.

Try avoiding this problem altogether by sticking with patterns that are familiar to .NET developers (as you have it already) - it is generally acceptable for array primitives to be passed around and trusting other code not to do strange or malicious things - the .NET Framework is teeming with this.

Community
  • 1
  • 1
Biscuits
  • 1,767
  • 1
  • 14
  • 22