有了这个.NET事件,传入这个IList实例可以吗?
我有以下代码:-
while (....)
{
var foo = DoTheFooShakeShakeShake(..);
foos.Add(foo); // foos is an IList<Foo>, btw and is new'd, above.
if (foos.Count % 100 == 0)
{
var e = new CustomFooEventArgs { UserId = whatever, Foos = foos };
OnFooPewPew(this, e);
foos.Clear();
}
}
// We still might have some foo's left over.. so send em off also.
// Excuse the woeful var names, below.
var e2 = new CustomFooEventArgs { UserId = whatever, Foos = foos };
OnFooPewPew(this, e2);
因此,我在某个 while/循环条件下获取所有 foo。每 100 个 foo's i 就会触发一个事件,将 foo's 列表传递给订阅者。然后我清除这个 foos 列表。一旦循环完成,我就会向订阅者发送任何剩余的 foo。
所以 - 如果我触发一个事件,其中包含 foo 的列表...然后我清除该列表.. 这是否意味着订阅者可以获得该列表,该列表现在为空?我应该传递列表的副本...然后清除原始列表吗?
i've got the following code :-
while (....)
{
var foo = DoTheFooShakeShakeShake(..);
foos.Add(foo); // foos is an IList<Foo>, btw and is new'd, above.
if (foos.Count % 100 == 0)
{
var e = new CustomFooEventArgs { UserId = whatever, Foos = foos };
OnFooPewPew(this, e);
foos.Clear();
}
}
// We still might have some foo's left over.. so send em off also.
// Excuse the woeful var names, below.
var e2 = new CustomFooEventArgs { UserId = whatever, Foos = foos };
OnFooPewPew(this, e2);
So, i grab all the foo's for some while/loop condition. Every 100 foo's i then fire an event, which passes the list of foo's off to the subscriber. I then clear this list of foos. Once the loop is finished, i then fire off any remaining foo's to the subscriber.
So - if i fire off an event, which contains the list of foo's ... and then i CLEAR that list .. will that mean that the subscriber can possibly get that list, which is now empty? Should I be passing across a COPY of the list ... and then clearing the original list?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
忘记清除吧,你改变列表的事实将会对订阅你的事件的对象造成严重破坏。 如果他们保留返回的列表,那么您在添加到列表或时随时都会更改数据。或清除列表。
您不仅可以扰乱订阅者,他们也可以扰乱您,因为他们可以改变列表并影响您自己的流程。
如果这不是所需的行为(我不认为它是),那么您甚至不需要发送副本,而是发送
IEnumerable
或ReadOnlyCollection
;Foo>
。因为即使您发送了一份副本,如果您有多个订阅者,他们都会收到相同的副本,因此他们的突变仍然会对彼此造成严重破坏。Forget about clearing, the fact that you're mutating the list at all is going to wreak havoc for objects that subscribe to your event. If they persist the list that is returned, you're going to be changing the data anytime you add to the list or clear it.
Not only can you mess the subscriber up, they can mess with you, as they can mutate the list and affect your own process.
If that is not the desired behavior (and I can't think that it is), you're going to want to send not even a copy, but an
IEnumerable<Foo>
orReadOnlyCollection<Foo>
. Because even if you send a copy, if you have multiple subscribers, they'll all receive the same copy, so their mutations will still wreak havoc for one another.当您清除列表时,事件处理程序将已经执行(它们是同步调用的),因此这不是问题。
但是,您应该避免传递列表本身,而应该传递一个副本。否则,事件订阅者可以保留对列表的引用并以不可预测的方式弄乱它......
By the time you clear the list, the event handlers will already have been executed (they're called synchronously), so it's not an issue.
However, you should avoid passing the list itself, you should pass a copy. Otherwise the event subscribers can keep a reference to the list and mess with it in unpredictable ways...
假设您可以控制所有订阅者并且仅在一个线程上工作,是的,这很好。否则,如果您无法控制订阅者(谁知道他们会做什么?)或者您正在使用多个线程处理发送的集合,则应考虑发送该集合的副本。
Assuming you have control over all the subscribers and are working on one thread only, yes, that is fine. Otherwise, if you do not have control over the subscribers (who knows what they will do?) or you are working with the sent collection using multiple threads, you should consider sending a copy of that collection.
我更愿意通过评论来做到这一点,但没有声誉:-)
安东尼的答案,您无法控制接收者,是确保您传递的列表副本是
ReadOnlyCollection
(*)。如果您只是将列表复制为另一个List
或其他可变集合,即使CustomFooEventArgs
将Foos
定义为非可变接口,例如作为IEnumerable
,一个特别卑鄙的接收者可以将Foos
转换为List
并改变它。至于 Thomas 的回答,使用
BeginInvoke
阻止事件接收器生成异步任务没有任何作用,除非我遗漏了一些东西。(*) 我可能会将其定义为
CustomFooEventArgs
中的IEnumerable
,但使用ReadOnlyCollection
的事实是恕我直言,实施细节。I would have preferred to do this with comments, but don't have the reputation :-)
The paranoid extension of Anthony's answer, where you don't have control of receivers, is to ensure the list copy you pass out is an
ReadOnlyCollection<Foo>
(*). If you simply copy your list as anotherList<Foo>
or other mutable collection, even ifCustomFooEventArgs
definesFoos
as a non-mutable interface such asIEnumerable<Foo>
, a particularly dastardly receiver could castFoos
as aList<Foo>
and mutate it.As for Thomas' answer, there is nothing from stopping the event receivers spawning an Async task using
BeginInvoke
, unless I'm missing something.(*) I'd probably have it defined as
IEnumerable<Foo>
inCustomFooEventArgs
though, the fact aReadOnlyCollection<Foo>
is used is an implementation detail IMHO.