在 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);
}
我的理解是相同的数组实例被传递给每个事件处理程序。
如果其中一个处理程序修改,这会导致以后出现问题吗
在其他处理程序开始处理之前的数组?
如果是这样,有什么好的补救方法?
如果您可以选择将其设为 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 充满了这个。
我有一个 C# class,它包装了一个 UDP 套接字,以便更轻松地接收和处理网络数据。
每当收到数据时,都会触发一个事件,并将数据作为参数传递:
public event Action<byte[]> DataReceived = delegate(byte[] data) { };
我收到数据并像这样触发事件:
while (socket.IsBound)
{
var buffer = new byte[MaximumDataLength];
socket.Receive(buffer);
DataReceived(buffer);
}
我的理解是相同的数组实例被传递给每个事件处理程序。
如果其中一个处理程序修改,这会导致以后出现问题吗 在其他处理程序开始处理之前的数组?
如果是这样,有什么好的补救方法?
如果您可以选择将其设为 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 充满了这个。