События + шаблон адаптера - PullRequest
3 голосов
/ 13 января 2011

У меня есть шаблон адаптера для универсального класса, который по существу адаптируется между типами:

class A<T> { event EventHandler e; }
class Aadapter<T1, T2> : A<T1> { A<T2> a; Aadapter(A<T2> _a) { a = _a; }  }

Проблема в том, что A содержит событие.Я хочу, чтобы все обработчики событий, назначенные адаптеру, перешли на.

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

Идея в том, что А почти что просто А, но нам нужен способадаптировать их.Из-за способа работы события я не могу, как эффективно сделать это, кроме как вручную добавить два обработчика события, и когда они вызываются, они «ретранслируют» другое событие.Это не красиво, хотя, и было бы намного лучше, если бы у меня было что-то вроде

class A<T> { event EventHandler e; }
class Aadapter<T1, T2> : A<T1> { event *e; A<T2> a; Aadapter(A<T2> _a) { a = _a; e = a.e; }  }

, в некотором смысле у нас есть указатель на событие, которому мы можем назначить событие a2.

Я сомневаюсь, что есть какой-то простой способ, но, возможно, у кого-то есть идея заставить его работать.

(Кстати, я понимаю, что это возможно с виртуальными событиями, но я бы хотел этого избежать, есливсе возможно)

Ответы [ 3 ]

2 голосов
/ 13 января 2011

Я думаю, что это то, что вам нужно:

    class A<T>
    {
        public virtual event EventHandler e;
    }

    class Aadapter<T1, T2> : A<T1> 
    { 
        A<T2> a; 
        Aadapter(A<T2> _a) { a = _a; } 
        public override event EventHandler  e
        {
            add { a.e += value; }
            remove { a.e -= value; }
        }
    }

Или цепочка

class A<T>
{
    public event EventHandler e;

    protected void ChainEvent(object sender, EventArgs eventArgs)
    {
        e(sender, eventArgs);
    }
}
class Aadapter<T1, T2> : A<T1> 
{ 
    A<T2> a; 
    Aadapter(A<T2> _a)
    {
        a = _a;
        a.e += ChainEvent;
    }
}
0 голосов
/ 13 января 2011

Пример, показывающий «стандартные» методы решения проблемы. В первом используются виртуальные события / методы, а во втором - схема пересылки с «двойным концом». У обоих есть свои плюсы и минусы, но было бы неплохо, если бы существовал более простой метод, который не увеличивался в зависимости от количества событий. Мы хотели бы объединить два события в одно, а не косвенно, что и делает весь этот код. (указатели были бы таким методом, если бы они были возможны в C #)

//#define __virtual
#define __direct

using System;
using System.Collections.Generic;
using System.Text;



namespace VirtualEvents
{



    #if __virtual
    #region
    public class A<T> 
    { 
        public virtual event EventHandler e;

        public virtual void Fire() { e(this, null); }
    }

    public class Aadapter<T1, T2> : A<T1> 
    { 
        A<T2> a;


        public override event EventHandler e
        {
            add { a.e += new EventHandler(value); }
            remove { a.e -= new EventHandler(value); }
        }

        public override void Fire()
        {
            a.Fire();
        }

        public Aadapter(A<T2> _a) 
        { 
            a = _a; 
        } 
    }
    #endregion
    #elif __direct
    #region

    public delegate EventHandler EventHandlerPtr();
        public class eventPtr
        {
            public EventHandler _event;
        }
    public class A<T>
    {


        //internal EventHandler _event;
        public eventPtr _event = new eventPtr();

        public event EventHandler e
        {
            add { _event._event += value; }
            remove { _event._event -= value; }
        }

        public void Fire() { _event._event(this, null); }


    }

    public class Aadapter<T1, T2> : A<T1>
    {
        A<T2> a;

        public Aadapter(A<T2> _a)
        {
            a = _a;
            this._event = a._event;
        }
    }

    #endregion
    #else
    #region 
    public class A<T>
    {
        public event EventHandler e;

        public void Fire() { e(this, null); }
    }

    public class Aadapter<T1, T2> : A<T1>
    {
        A<T2> a;

        public Aadapter(A<T2> _a)
        {
            a = _a;

            a.e += new EventHandler(a_e);
            e += new EventHandler(Aadapter_e);
        }

        void Aadapter_e(object sender, EventArgs e)
        {
            a.e -= new EventHandler(a_e);
            a.Fire();
            a.e += new EventHandler(a_e);
        }

        void a_e(object sender, EventArgs e)
        {       
            this.e -= new EventHandler(Aadapter_e);
            Fire(); 
            this.e += new EventHandler(Aadapter_e);
        }
    }
    #endregion
    #endif


    class Program
    {
        static void Main(string[] args)
        {

            var a = new A<double>();
            var q = new Aadapter<int, double>(a);

            a.e += new EventHandler(a_e);
            q.e += new EventHandler(q_e);


            a.Fire();
            q.Fire();
            ((A<int>)q).Fire();

            Console.ReadKey();
        }

        static void a_e(object sender, EventArgs e)
        {
            Console.WriteLine("From a");
        }

        static void q_e(object sender, EventArgs e)
        {
            Console.WriteLine("From q");
        }

    }
}

(редактировать: теперь в код добавлен новый метод, который оборачивает событие в класс, который теперь позволяет легко и эффективно назначать события, что представляет собой «указатель». Надеемся, что кто-то может улучшить их еще больше.) *

0 голосов
/ 13 января 2011

Почему подписка и переадресация событий не такие красивые? Я нахожу это элегантным.

Это соответствует способу реализации остальной части адаптера.

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

Например, если вы адаптируете класс, который реализует INotifyPropertyChanged, к интерфейсу, который не имеет, но предоставляет несколько свойств, таких как «TitleChanged» и «MaxLengthChanged», вы бы тогда не использовали указатель , Ваш адаптер выставит эти два события, и потребители подпишутся. Ваш адаптер будет подписываться на событие PropertyChanged и вызывать «TitleChanged» только тогда, когда он получает уведомление о том, что «Title» был изменен, а «MaxLengthChanged» только тогда, когда он получает уведомление о том, что «MaxLength» был изменен. Все остальные уведомления будут игнорироваться.

Я предпочитаю этот подход, так как считаю его простым, последовательным и верным шаблону.

...