Действительно ли возможно мешать нескольким подписчикам подписаться на событие?
Я создал быстрый отрывок в качестве примера, чтобы дать моему вопросу некоторый контекст, но к сожалению я не могу проверить его прямо сейчас, потому что я не в моем ПРОТИВ машины.
Цель к:
Действительно ли это возможно?
public delegate List<IBaseWindow> GetWindowListDelegate();
public static event GetWindowListDelegate GetWindowListEvent;
public List<IBaseWindow> GetWindowList() {
if (GetWindowListEvent == null) {
return new List<IBaseWindow>();
}
return GetWindowListEvent();
}
Примечание: Я использую.NET 3.5 sp1.
Похоже, вам не нужно событие - просто разоблачить сам делегат и позволить абонентам устанавливать ссылку делегата самостоятельно.
Просто для завершения ответа Джона, вот рабочая реализация события, которое позволяет только один обработчик:
class Foo
{
private EventHandler _bar;
public event EventHandler Bar
{
add
{
if (_bar != null || value.GetInvocationList().Length > 1)
{
throw new InvalidOperationException("Only one handler allowed");
}
_bar = (EventHandler)Delegate.Combine(_bar, value);
}
remove
{
_bar = (EventHandler)Delegate.Remove(_bar, value);
}
}
}
обратите внимание, что выяснение делегата, а не события, не мешает нескольким обработчикам: поскольку делегаты .NET - это многоадрес, один делегат может представлять вызов нескольким методам. Однако вы можете выдержать делегат в качестве свойства и выполнять в установке той же проверки, что и в коде выше.
Во всяком случае, как указывали другие, это, вероятно, не очень хорошая идея, чтобы предотвратить несколько обработчиков для мероприятия ... было бы очень запутано разработчикам, которые его используют.
Вы можете использовать Accessors для достижения этого. Что-то вроде следующее:
private EventHandler _h;
public event EventHandler H {
add {
if (...) { // Your conditions here.
// Warning (as per comments): clients may not
// expect problems to occur when adding listeners!
_h += value;
}
}
remove {
_h -= value;
}
}
Как отмечает Эндрю, вам не нужны события для достижения этого. Есть ли некоторые особые причина, по которой они нуждаются в них?
Конечно, можно добиться того, что вы хотите сделать, но он не соответствует конвенции - я призваю вас призвать к другому решению, которое не включает в себя события.
Как объяснено Jon Skeet , публичные события являются имуществующими имущеными обертками вокруг многоадресного делегата.
Вы можете подумать о стандартной реализации события как список функций, которые будут называться, когда что-то происходит.
// From the above link:
// the exposed event
public event EventHandler MyEvent
// multicast delegate field
private EventHandler _myEvent;
// property-like add & remove handlers
public event EventHandler MyEvent
{
add
{
lock (this)
{
_myEvent += value;
}
}
remove
{
lock (this)
{
_myEvent -= value;
}
}
}
... Когда разработчик видит такое событие, они ожидают, что смогут подписаться на него без выпуска, поскольку событие в основном говорит: «Любое количество типов может зарегистрироваться для получения этого уведомления о событиях».
Похоже, вы хотите позволить кому-то установить реализацию, которая получает список Windows. То, что я бы предложил сделать, - это позволяет людям вручную пройти в делегате, затем провести один делегат . Сделать его явным, что есть только один способ установить его; Если вообще возможно, я бы порекомендовал использовать инъекцию конструктора, поскольку это удаляет всю двусмысленность - вы можете установить только экземпляр делегата только один раз на конструкцию, то он больше не модифицируется Public API (поэтому класс B не может засориться с помощью делегата, который уже был установлен по классу а).
E.g.
public class CallsDelegateToDoSomething
{
private Func<List<IBaseWindow>> m_windowLister;
public CallsDelegateToDoSomething(Func<List<IBaseWindow>> windowFunc)
{
m_windowLister = windowFunc;
}
public List<IBaseWindow> GetWindowList()
{
if (windowLister == null)
{
return new List<IBaseWindow>();
}
return m_windowLister();
}
}
Если ваш дизайн не допускает этого, то просто создайте SetWindowlister (Func
и > Windowlister)
relowwindowlister ()
методы.