在 C# 中,将数组传递给事件处理程序时如何避免修改?

In C#, how can I avoid modifications when passing an array to event handlers?

我有一个 C# class,它包装了一个 UDP 套接字,以便更轻松地接收和处理网络数据。

每当收到数据时,都会触发一个事件,并将数据作为参数传递:

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

我收到数据并像这样触发事件:

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

    socket.Receive(buffer);

    DataReceived(buffer);
}

我的理解是相同的数组实例被传递给每个事件处理程序。

  1. 如果其中一个处理程序修改,这会导致以后出现问题吗 在其他处理程序开始处理之前的数组?

  2. 如果是这样,有什么好的补救方法?

如果您可以选择将其设为 IEnumerable<byte>,如:

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

然后你可以用任何可枚举的东西来调用它,但是委托以不可修改的形式得到它。

(如果这对您不起作用,总有 ReadOnlyCollection<T>


澄清:

arrays implement IEnumerable<>(自 .net 2.0 起)您可以将 byte[] 直接传递给处理程序:

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

如果你想让阅读代码的人清楚地知道你可以随时投射:

DataReceived((IEnumerable<byte>)buffer);

方法一

使用 Array.AsReadOnly<T> 扩展方法以高效的方式创建 ReadOnlyCollection<T>

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

方法二

您可以为 ArraySegment<T> 实现一个包装器,使其成为只读的,如本回答中所建议的那样。

与列表或其他集合相比,使用 ArraySegment 有很多好处。

what is the use of ArraySegment<T> class?

备注

一个典型的想法可能是制作字节数组的副本,但这可能对您不起作用,因为每个事件处理程序仍会访问相同的副本。

尝试通过坚持使用 .NET 开发人员熟悉的模式(因为您已经拥有)来完全避免这个问题 - 传递数组基元通常是可以接受的,并且相信其他代码不会做奇怪或恶意的事情东西 - .NET Framework 充满了这个。