BeginUpdate和EndUpdate的实现

时间:2011-10-24 03:48:37

标签: c#

1)我正在研究一个项目,我看到了这段代码,我不明白Monitor.Lock语句有什么意义。有人可以解释它试图做什么吗?

2)参数名称中的postscript下划线真的很烦人,有谁看过这个命名约定?

public class FieldsChangeableHelper<T> : IFieldsChangeable<T>
{
    object _lock;
    int _lockCount;
    FieldChanges<T> _changes;

    public FieldsChangeableHelper()
    {
        _lock = new object();
        _lockCount = 0;
    }

    public void AddChange(T field_, object oldValue_)
    {
        if (_changes == null)
            _changes = new FieldChanges<T>(field_, oldValue_);
        else
            _changes.AddChange(field_, oldValue_);
        if (RaiseEvent(_changes))
            _changes = null;
    }

    #region IFieldsChangeable Members

    public void BeginUpdate()
    {
        if (System.Threading.Interlocked.Increment(ref _lockCount) == 1)
            Monitor.Enter(_lock);
    }

    public void EndUpdate()
    {
        if (System.Threading.Interlocked.Decrement(ref _lockCount) == 0)
        {
            FieldChanges<T> changes = _changes;
            _changes = null;
            Monitor.Exit(_lock);
            RaiseEvent(changes);
        }
    }


    protected bool RaiseEvent(FieldChanges<T> changes_)
    {
        if (_lockCount == 0 && Changed != null && changes_ != null)
        {
            Changed(this, changes_);
            return true;
        }
        return false;
    }

    public event FieldsChanged<T> Changed;

    #endregion
}

2 个答案:

答案 0 :(得分:0)

当多个线程尝试并行执行同一块时,Monitor.Lock会锁定代码部分。它是为了确保只有1个人正在改变/执行上下文。看看MSDN。

尽管最佳做法是锁定对象始终是静态的,但在您的情况下却不是。如果您在开放类型上实例化多个对象,则可能会出现问题。

注意一件事,在泛型静态上打开T对于不同类型是不同的,即在你的情况下Open Type类中的静态成员对于T即DateTime,string等是不同的。

在csharp中,类型的私有成员通常以前缀_

命名

答案 1 :(得分:0)

我读它的方式:BeginUpdate()确保当前线程调用具有对实例的独占访问权限,并且一旦调用EndUpdate,实际上将更改事件的批处理和引发。作者希望自己处理递归(例如,在同一个线程上多次调用BeginUpdate())和一个批量UpdateEvents的机制,直到释放锁之后。因为,当您仍然锁定自己时,在提升事件时可能存在死锁。事件订阅者可能希望访问您的成员,因此必须锁定已锁定的发件人实例。

不需要整个条件锁定(如果我的分析是正确的),因为基于Monitor类的锁是递归和计数的。

锁定机制存在另一个问题,即:当前一个线程持有锁定时。第二个线程甚至不会等待锁定,但只是继续没有锁定,因为锁是有条件的!这似乎是一个大错误!

关于命名约定。我自己用它来区分私人参数和当地人。它是许多C#编码惯例推荐的偏好。这有助于这样的情况:

void Method(int number)
{
    // no need to refer to this since:
    //this.number = number; 
    // can be replaced with
    _number = number;
}