Унаследованные события C # с пользовательскими аргументами - PullRequest
3 голосов
/ 06 сентября 2011

Я пытаюсь указать событие в интерфейсе с пользовательскими аргументами. Мне нужно, чтобы аргумент события был объектом. Я попытался сократить следующий код настолько, насколько это возможно. В настоящее время я получаю следующую ошибку.

ArgumentNullException: Argument cannot be null.
Parameter name: obj
LittleObject.IObject.add_ChangeEvent (System.EventHandler`1 value) 
(at LittleObject.cs line : [where the comment is])

код

public class ChangeEventArgs : EventArgs {
    public ChangeEventArgs(SomeClass c){ someClass = c;}
    public SomeClass someClass;
}


public interface IObject {
    void OnChangeEvent(ChangeEventArgs e);
    event EventHandler<ChangeEventArgs> ChangeEvent;
}


public class LittleObject : IObject{    

    public event EventHandler<ChangeEventArgs> ChangeEvent;

    public fireEvent(){
        OnChangeEvent(new ChangeEventArgs(new SomeClass()));
    }

    event EventHandler<ChangeEventArgs> IObject.ChangeEvent{
        add{                                // error here
            lock (ChangeEvent) {
                ChangeEvent += value;
             }
        }
        remove{
            lock (ChangeEvent){
                ChangeEvent -= value;
            }
        }
    }

    public void OnChangeEvent(ChangeEventArgs e){
        if(ChangeEvent != null) {
            ChangeEvent(this, e);
        }
    }
}


public class Main {

    IObject currentObject;

    void init(){
        currentObject = new IObject();
        currentObject.ChangeEvent += new EventHandler<ChangeEventArgs>(OnChangeEvent);
    }

    void doStuff(){
        currentObject.fireEvent();
    }

    public void OnChangeEvent(object sender, ChangeEventArgs e) {
        SomeClass someClass = e.someClass;
    }
}

1 Ответ

7 голосов
/ 06 сентября 2011

Этот код довольно грязный, но я считаю, что причина, по которой вы получаете исключение, заключается в том, что вы блокируете ссылку null.

Когда вы делаете:

add
{
    lock (ChangeEvent) { ... }
}

Компилятор на самом деле использует приватное поле , поддерживающее событие ChangeEvent (см. похожее на поле событие ). Обратите внимание, что начальное значение этого поля null (ему не было явно назначено начальное значение, скажем, через инициализатор поля).

Теперь, когда кто-то подписывается на событие «обтекания» (someObject.ChangeEvent += ...) в первый раз, вызывается ваш пользовательский add метод доступа, что приводит к попытке заблокировать объект ссылается на это поле (для блокировки на самом деле нужны некоторые данные в заголовке объекта, называемом «блоком синхронизации»). Конечно, такого объекта не существует, и именно поэтому блокировка срабатывает.

Что касается странного параметра obj, то это параметр из Monitor.TryEnter(object obj, ref bool lockTaken), к которому и сводится оператор блокировки C # (предыдущие версии C # предназначались для другого метода).

Честно говоря, я бы настоятельно рекомендовал переработать весь этот кусок кода.

РЕДАКТИРОВАТЬ: Уточнил использование события обтекания.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...