miércoles, 16 de diciembre de 2015

C# using event Action delegate

Un popular patrón de diseño (una solución reusable para un problema recurrente) en el desarrollo de una aplicación es el publish-subscribe (editor-subscriptor). Usted subscribe a un evento y después lo notifica cuando el publisher de un evento lanza el nuevo evento. Este es usado para establecer bajo acoplamiento entre componentes es una aplicación.

Los delegados forman la base de un sistema basado en eventos en C#. El siguiente ejemplo presenta como una clase expone un delegado publico y como lanza a éste.

using System;

namespace UsingActionToExposeEvent
{
    public class Pub
    {
        public Action OnChange{get; set;}

        public void Raise()
        {
            if(OnChange != null)
            {
                OnChange();
            }
        }

    }

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

        public static void CreateAndRaise()
        {
            Pub p = new Pub();
            p.OnChange += () => Console.WriteLine("Event raised to method 1");
            p.OnChange += () => Console.WriteLine("Event raised to method 2");

            p.Raise();

        }
    }
}

En este ejemplo, la clase Pub lanza el evento. Sin embargo, nada previene a usuarios esternos de la clase lanzar el evento. Tal y como llamamos a p.OnChange, cualquier usuario de la clase puede lanzar el evento para todos los subscriptores.

Para superar estas debilidades, C# usa la palabra clave event. El ejemplo anterior modifica la clase usando la sintaxis event.

using System;

namespace UsingActionToExposeEvent
{
    public class Pub
    {
        public event Action OnChange = delegate { };

        public void Raise()
        {
            if(OnChange != null)
            {
                OnChange();
            }
        }

    }

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

        public static void CreateAndRaise()
        {
            Pub p = new Pub();
            p.OnChange += () => Console.WriteLine("Event raised to method 1");
            p.OnChange += () => Console.WriteLine("Event raised to method 2");

            p.Raise();

        }
    }
}

Usando la sintaxis event, hay un par de cambios interesantes. Primero usted deja de usar una propiedad publica pero a un campo publico. Normalmente, este podría ser un paso atras. Sin embargo con la sintaxis event, el compilador protege su campo de un acceso no deseado.

Un evento no puede ser directamente asignado por el operador (con el = en vez del +=). Así no puede tener el riesgo de que alguien remueva a todos los previos subscriptores, así con la sintaxis delegate.

Otro cambio es que los usuarios no externos pueden lanzar su evento. Este puede ser lanzado solamente por aquellos que son parte de la clase que define el evento.

El siguiente ejemplo usa una sintaxis especial par inicializar el evento como un delegado vacio. De esta forma, usted puede remover el nul alrededor del lanzador del evento porque puede ser cierto que el evento sea siempre nulo. Usuarios externos a su clase no pueden definir un valor para el evento nulo, usted puede con seguridad asumir que este siempre tenga un valor.

Hay sin embargo un cambio que debe mantener para seguir las convenciones de codificación den .NET Framework . En vez de usar el tipo Action para su evento, usted debería usar el EventHandler o EventHandler<T>. El EventHandler es declarado como en el siguiente ejemplo.

using System;

namespace CustomEventArguments
{
    public class MyArgs : EventArgs
    {
        public int Value { get; set; }

        public MyArgs(int value)
        {
            Value = value;
        }
    }

    public class Pub
    {
        public event EventHandler<MyArgs> OnChange = delegate { };
        public void Raise()
        {
            OnChange(this, new MyArgs(42));
        }
    }

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

        public static void CreateAndRaise()
        {
            Pub p = new Pub();
            p.OnChange += (sender, e)
            => Console.WriteLine("Event raised: {0}", e.Value);

            p.Raise();
        }
    }
}

La clase Pub usa un EventHandler<MyArgs>, que especifican el tipo de argumentos event. Cuando se lanza este event, usted requiere pasar una instancia de MyAgrs. Suscribirse para el event puede acceder a los argumentos y usar a éste.

Aunque la implementación del event usa un campo publico, usted puede mantenerse en la construcción agregando y removiendo suscriptores. Este es llamado custom event accesor. El siguiente ejemplo crea un para un custom event accesor evento.

NOTA.
Observe de forma detenida  la declaración del delegado, tienen el mismo nombre pero la diferencia esta en que en la declaración del delegado la  primera letra es minúscula: onChange.
La declaración para el manejo del delegado la primera letra es mayúscula: OnChange y tiene el aspecto de una propiedad.

using System;

namespace CustomEventAccessor
{
    public class MyArgs : EventArgs
    {
        public int Value { get; set; }

        public MyArgs(int value)
        {
            Value = value;
        }
    }

    public class Pub
    {
        private event EventHandler<MyArgs> onChange = delegate { };
        public event EventHandler<MyArgs> OnChange
        {
            add
            {
                lock (onChange)
                {
                    onChange += value;
                }
            }

            remove
            {
                lock (onChange)
                {
                    onChange -= value;
                }
            }

        }

        public void Raise()
        {
            onChange(this, new MyArgs(42));
        }

    }


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



Un custom event accessor se observa como una propiedad con un accessor get. En vez de get y set usted usa add y remove. Es importante colocar un lock en los subscriptores para agregar y remover para hacer segura la operación en un hilo seguro.

Referencia:
Exam Ref. 70-384 Programming in C#










No hay comentarios.:

Publicar un comentario