Назначение указателя на событие для последующего использования - PullRequest
0 голосов
/ 05 августа 2011

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

Кстати, если вы можете сформулировать вопрос в лучшем свете пожалуйста, не стесняйтесь давать свой 2с!

class CustomEventArgs : EventArgs
{
    public delegate void CustomEventHandler( Object sender, CustomEventArgs args );

    public int data;

    public CustomEventArgs (int _data)
    {
        data = _data;
    }
}

Это событие, которое мы будем использовать в этом примере.

class EventGenerator
{
    public event CustomEventArgs.CustomEventHandler WeOccasion;

    public EventGenerator ()
    {
        Task.Factory.StartNew( () =>
            {
                var index = 1;

                // just loop and generate events every now and then
                while (true)
                {   
                    Thread.Sleep( 1000 );
                    WeOccasion( this, new CustomEventArgs (++index));
                }
            });
    }
}

Этот класс просто циклически запускает события CustomEventHandler.

class EventActivity
{
    // EventActivity has an event of the same type as EventGenerator's 
    public event CustomEventArgs.CustomEventHandler WeOccasion;

    // this is the part I cant seem to get right
    public event CustomEventArgs.CustomEventHandler Source ( get; set; }

    public bool Active {
        set
        {
            if (value)
            {
                Source += DoWork;
            }
            else
            {
                Source -= DoWork;
            }
        }
    }

    private void DoWork( Object sender, CustomEventArgs frame);
}

Здесь мне действительно нужна помощь. Мне нужен почти указатель на событие в другом классе типа CustomEventHandler, которому я могу позже назначить обработчики событий при активации действия.

Вот пример использования, заключенный в класс;

class EventAssigner
{
    EventGenerator Generator;
    EventActivity DoSomeThing1;
    EventActivity DoSomeThing2;

    public EventAssigner ()
    {
        // init
        Generator = new EventGenerator();
        DoSomeThing1 = new EventActivity();
        DoSomeThing2 = new EventActivity();

        // assign sources
        DoSomeThing1.Source = Generator.WeOccasion;
        DoSomeThing2.Source = DoSomeThing1.WeOccasion;

        // activate the first activity
        DoSomeThing1.Active = true;
    }

    public void Activate2()
    {
        // activate the second activity
        DoSomeThing2.Active = true;
    }

    public void Deactivate2()
    {
        // deactivate the second activity
        DoSomeThing2.Active = false;
    }
}

Очевидно, что этот код не работает, и я полагаю, это то, что я спрашиваю. Можете ли вы заставить этот шаблон дизайна работать?

Ответы [ 2 ]

2 голосов
/ 05 августа 2011

То, что вы просите сделать, на самом деле невозможно с событиями .NET и, вероятно, не так желательно, как вы думаете. Немного предыстории должно помочь объяснить, почему:

Свойства имеют базовый шаблон с операциями get и set. Они вызываются путем доступа к свойству (для получения) и присвоения свойству (для набора):

var x = instance.Prop1; // access
instance.Prop1 = x; // assignment

Когда вы получаете доступ к событию извне класса (т.е. instance.Event), вам предоставляется «публичное» лицо, которое, как и свойства, имеет две операции: добавить обработчик и удалить обработчик. Они вызываются с использованием операторов += и -=.

instance.Event += this.Handler; // add
instance.Event -= this.Handler; // remove

Важно отметить, что в нем нет операции get - нет способа получить ссылку на событие вне класса ; Вы можете изменять только зарегистрированные обработчики.

Когда вы обращаетесь к событию из класса, вам присваивается «личное» лицо, которое по сути является специальной коллекцией делегатов (указателей функций) для зарегистрированных обработчиков событий. Когда вы вызываете делегата, вы на самом деле просите платформу перебрать зарегистрированные обработчики событий и вызвать их.

if(this.Event != null)
{
    this.Event.Invoke(e, args); // raise event
}

Это разделение публичного лица и частного лица - вот что позволяет вам иметь хорошее простое ключевое слово event, которое волшебным образом дает вам событие. Это также то, что мешает вам передать ссылку на событие вокруг.

Чтобы передать событие в методы регистрации, вы должны передать объект, к которому прикреплено событие. Если у вас есть несколько классов, которые реализуют одно и то же событие, и вы хотите зарегистрировать их все одинаково, вам нужно, чтобы они реализовали интерфейс с событием (да, события могут быть в интерфейсах) и напишите свой метод для принятия интерфейса как аргумент.

1 голос
/ 05 августа 2011

Если я правильно читаю, вам нужна строка

DoSomeThing1.Source = Generator.WeOccasion;

чтобы сохранить указатель на событие WeOccasion, чтобы вы могли добавить к нему вызов DoWork позже, верно?

Я не думаю, что это возможно с "нормальным" кодом, так как событие не является значением, а скорее как свойство. Рассмотрим следующий аналогичный код:

myProp = aPerson.Name; // attempt to save the name property for later
myProp = "Fred"; // intent is to set aPerson.Name = "Fred"

Если вы хотите, чтобы это работало, я бы предложил использовать отражение, чтобы найти событие, и добавить к нему метод EventInfo.AddEventHandler (http://msdn.microsoft.com/en-us/library/system.reflection.eventinfo.addeventhandler.aspx)

...