延迟事件处理直到事件被触发

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属性的修改可以触发其他属性更改,因此需要听众知道属性的修改已经完成.

Mat*_*son 4

只有执行修改的代码才能知道其批量更改何时完成。

我对类似的类所做的就是提供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)

  • 此模式的一个很好的 MSDN 示例来自 Control,其 [SuspendLayout](http://msdn.microsoft.com/en-us/library/system.windows.forms.control.suspendlayout.aspx) 和 [ResumeLayout](http ://msdn.microsoft.com/en-us/library/system.windows.forms.control.resumelayout.aspx) (2认同)