For*_*stC 12 c# events event-handling
在C#中,在实体完全修改之前,延迟处理所有已知事件的最佳方法是什么?比如说,实体 - MyEntity - 具有属性ID,名称和描述......
public class MyEntity
{
public Int32 ID { get; set; }
public String Name { get; set; }
public String Description { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
修改每个属性时,会为每个修改触发一个事件.
有时,ID是唯一已修改的属性,有时会修改所有属性.我希望修改事件的已注册侦听器等待,直到修改了"批处理"中修改的所有属性.
完成此任务的最佳方法是什么?
在我的脑海中,类似于UnitOfWork模式,可以在调用堆栈的顶层包装一个using语句围绕方法调用,但不知道如何实现这样的事情......
编辑:作为澄清......监听器通过应用程序分散,并在其他线程中执行.另一个actor设置 - 例如 - 它必须调用MyEntity.Name属性来设置值的名称.
由于设计原因,Name属性的修改可以触发其他属性更改,因此需要听众知道属性的修改已经完成.
只有执行修改的代码才能知道其批量更改何时完成。
我对类似的类所做的就是提供SuspendNotifications()和ResumeNotifications()方法,这些方法以明显的方式调用(即在进行一堆更改之前调用暂停,完成后调用恢复)。
它们在内部维护一个计数器,该计数器在 SuspendNotifications() 中递增并通过 ResumeNotifications() 递减,如果递减结果为零,则会发出通知。我这样做是因为有时我会修改一些属性,然后调用另一个方法来修改更多属性,并且该方法本身会调用挂起/恢复。
(如果简历被调用太多次,我会抛出异常。)
如果更改了多个属性,则最终通知不会命名正在更改的属性(因为有多个属性)。我想您可以积累已更改属性的列表并将其作为通知的一部分发出,但这听起来不太有用。
另请注意,线程安全对您来说可能是问题,也可能不是问题。您可能需要使用锁定和/或Interlocked.Increment()等。
另一件事是,当然,您最终需要在调用挂起/恢复时进行 try/catch,以防出现异常。您可以通过编写一个实现 IDisposable 的包装类并在其 Dispose 中调用resume来避免这种情况。
代码可能如下所示:
public void DoStuff()
{
try
{
_entity.SuspendNotifications();
setProperties();
}
finally
{
_entity.ResumeNotifications();
}
}
private setProperties()
{
_entity.ID = 123454;
_entity.Name = "Name";
_entity.Description = "Desc";
}
Run Code Online (Sandbox Code Playgroud)
[编辑]
如果您要引入一个接口,例如ISuspendableNotifications,您可以编写一个IDisposable包装类来简化事情。
下面的例子说明了这个概念;使用NotificationSuspender简化了(实际上消除了)try/catch 逻辑。
请注意,class Entity当然实际上并没有实现挂起/恢复或提供任何错误处理;这留给读者作为众所周知的练习。:)
using System;
namespace Demo
{
public interface ISuspendableNotifications
{
void SuspendNotifications();
void ResumeNotifications();
}
public sealed class NotificationSuspender: IDisposable
{
public NotificationSuspender(ISuspendableNotifications suspendableNotifications)
{
_suspendableNotifications = suspendableNotifications;
_suspendableNotifications.SuspendNotifications();
}
public void Dispose()
{
_suspendableNotifications.ResumeNotifications();
}
private readonly ISuspendableNotifications _suspendableNotifications;
}
public sealed class Entity: ISuspendableNotifications
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public void SuspendNotifications() {}
public void ResumeNotifications() {}
}
public static class Program
{
public static void Main(string[] args)
{
Entity entity = new Entity();
using (new NotificationSuspender(entity))
{
entity.Id = 123454;
entity.Name = "Name";
entity.Description = "Desc";
}
}
}
}
Run Code Online (Sandbox Code Playgroud)