基于集合的项目中事件的传播
我在.NET 4中有一个基于集合的项目。我的意思是,我有一个主集合,称之为“系统”,它由框架组成,每个框架由卡片组成,而卡片又由卡片组成的频道。所以,它看起来像系统->框架->卡->通道。所有这些都被表示为对象,并且它们之间存在父子关系。本质上,Channel只暴露给Card,Card只暴露给Frame,Frame只暴露给System。
理想情况下,我希望仅向外界公开 System 类的方法。然而,在 Channel、Card 和 Frame 类中发生了一些关键事件。目前,我处理它们的方式是通过传播。假设 Channel 中发生了一个事件。该事件首先在 Card 中引发,然后在 Frame 中引发,最后在 System 中引发。您可以看到这如何产生大量代码。但我主要关心的不是代码,而是性能。
您认为这种传播会严重影响我的表现吗?有没有办法让它更有效率?我还有什么其他选择?我的收藏相对较少。系统为1,帧数< 16、卡片< 256、通道< 8192. 大部分数据存储在 Channel 类中,该类中只有原始对象。
编辑
这是我在 Card 中针对由 Channel 引发的事件的代码:
protected virtual void OnChannelPropertyChanged(Object sender, PFPropertyChangedEventArgs e)
{
try
{
EventHandler<PFPropertyChangedEventArgs> handler = ChannelPropertyChanged;
TestEventArgs_ChannelPropertyChanged = e;
if (handler != null)
{
handler(sender, e);
}
}
catch (Exception ex)
{
Milltown.MTCore.mtException mtEx = new Milltown.MTCore.mtException((int)PFExceptions.Exception_Hidden_FuctionLevel, ex,
PFCommonVariables.ApplicationPlatform, PFCommonVariables.ApplicationDataSource, "PFCard:OnChannelPropertyChanged");
}
}
当我将 Channel 添加到 Card 类中的 Card 时,我调用:
channel.ChannelPropertyChanged += this.OnChannelPropertyChanged;
I have a collection-based project in .NET 4. What I mean is that, I have a master collection, call it "System", which is made up of frames, which are each made up of cards, which are in turn made up of channels. So, it looks like System->Frame->Card->Channel. All these are represented as objects, and there is a Parent-Child relationship between them. Essentially, Channel is only exposed to Card, Card is only exposed to Frame, and Frame is only exposed to System.
Ideally, I would wish to expose methods only from the System class to the outside world. However, there are crucial events that occur in Channel, Card, and Frame classes. Currently, the way I handle them is through propagation. Suppose an event occurred in Channel. This event is first raised in Card, then in Frame, and then finally in System. You can see how this results in a lot of code. But my main concern is not of code, but of performance.
Do you think this propagation effects my performance badly? Is there a way to make it more efficient? What other options do I have? My collections are relatively small. System is 1, Frames < 16, Cards < 256, Channels < 8192. Most of the data is stored in the Channel class, which only has primitive objects within it.
EDITS
Here is the code I have in Card for an event that is raised by a Channel:
protected virtual void OnChannelPropertyChanged(Object sender, PFPropertyChangedEventArgs e)
{
try
{
EventHandler<PFPropertyChangedEventArgs> handler = ChannelPropertyChanged;
TestEventArgs_ChannelPropertyChanged = e;
if (handler != null)
{
handler(sender, e);
}
}
catch (Exception ex)
{
Milltown.MTCore.mtException mtEx = new Milltown.MTCore.mtException((int)PFExceptions.Exception_Hidden_FuctionLevel, ex,
PFCommonVariables.ApplicationPlatform, PFCommonVariables.ApplicationDataSource, "PFCard:OnChannelPropertyChanged");
}
}
And when I add a Channel to a Card within the Card class, I call:
channel.ChannelPropertyChanged += this.OnChannelPropertyChanged;
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您可以在 System 类中执行此操作:
因此,如果客户端执行此操作,则
处理程序实际上会附加到 Frame 类中的 Event。
You can do this in the System class:
So if a client does this
The handler is really attached to the Event in the Frame class.
回答是否影响性能的唯一方法是测试它:尝试一种传播事件的方法,然后尝试另一种直接附加的方法。看看哪个更快。
话虽如此,我无法想象当您有几个连续的委托调用而不是一次时,您会发现对性能有多大(如果有的话)可衡量的影响。是的,委托的调用速度比实际方法稍慢,因此,在所有条件相同的情况下,添加更多级别的间接访问比使用常规方法调用的相同级别具有更大的影响,但这有点过早优化的味道。
如果有人问如何做你想做的事,我会推荐你的方法。就这样吧,除非有问题。
编辑
为了回应您对另一个答案的评论,我想扩展。 C# 事件具有所谓的“属性语法”。如果在类中显式实现,它看起来像这样:(
实际上,它使用
Delegate.Combine
,但这在这里并不重要)当您附加到事件时,它实际上调用
add< /code> 代码,传入委托作为
value
附加;remove
也是如此。当您使用如下所示的简写事件语法时:
它实际上会在幕后生成与我上面发布的代码非常相似的代码。但是,如果您将其明确化,则可以在
add
和remove
处理程序中执行任何您喜欢的操作。这意味着您可以将目标委托重定向到其他地方。在另一个答案的情况下,它将委托重定向到子对象。当且仅当满足以下条件时,此方法才有效:
object
)是可以接受的如果你有多个孩子,技术上是可以做到的(你可以循环遍历并附加到
add
中的所有孩子,并在add
中删除所有孩子>remove),但管理起来要困难得多。如果相关对象或对象集合在事件附加后可能发生变化,那么协调实际上变得不可能。此外,如果您的事件遵循推荐的事件实践(您将触发对象作为
sender
传递),那么由于您将目标直接附加到子事件而不是自己引发它,那么您将通过此参数公开对子对象的引用。我不知道这是否与您相关或是否可以接受,但这是应该考虑的事情。The only way to answer whether or not affects your performance would be to test it: try it one way where you propogate the events, then another where you attach directly. See which is faster.
That being said, I can't imagine that you're going to find much--if any--measurable impact on performance when you have a few sequential delegate invocations instead of just one. Yes, delegates are slightly slower to invoke than actual methods, so, all things being equal, adding more levels of indirection has a bigger impact than the same level with regular method calls, but this smells of premature optimization.
Your approach is what I would recommend if someone asked how to do what you're after. Go with it unless it's a problem.
EDIT
In response to your comment on another answer, I wanted to expand. C# events have what's called "property syntax". If implemented explicitly in a class, it looks something like this:
(Actually, it uses
Delegate.Combine
, but that's immaterial here)When you attach to an event, it actually calls the
add
code, passing in the delegate to attach asvalue
; the same is true forremove
.When you use the shorthand event syntax like this:
It actually generates code under the covers that's very similar to what I posted above. However, if you make it explicit, you can do whatever you like in the
add
andremove
handlers. This means that you can redirect the target delegate somewhere else. In the case of the other answer, it's redirecting the delegate to a child object.This will work if and only if the following are true:
object
) is acceptableIf you have multiple children, it's technically possible to do (you could just loop through and attach to all of them in the
add
and remove all of them inremove
), but is much more difficult to manage. If the related object or the collection of objects can change after the event is attached, then it becomes virtually impossible to coordinate.Additionally, if your events follow the recommended practices for events (where you pass the triggering object as
sender
), then because you're attaching the target directly to the child event rather than raising it yourself, then you'll be exposing a reference to the child object through this argument. I have no idea if that's relevant or acceptable to you, but it's something that should be considered.