EDICIÓN: Después de que Joel Coehoorns excelente respuesta, entiendo que necesito para ser más específicos, así que he modificado el código para estar más cerca de la cosa que estoy tratando de entender…

Eventos: Como yo lo entiendo, en el fondo, los eventos son “colección” de EventHandlers aka Delegados que serán ejecutadas al caso planteado. Así que para mí significa que si el objeto Y ha evento E y del objeto X se suscribe al evento Y. E, entonces Y se han de hacer referencia a la X, ya que Y debe ejecutar el método situado en X, de esa manera, X no pueden ser recogidos, y que lo entiendo.

//Creates reference to this (b) in a.
a.EventHappened += new EventHandler(this.HandleEvent);

Pero no es lo que Joel Coehoorn dice…

Sin embargo, hay un problema con los eventos que a veces la gente le gusta usar IDisposable con tipos que tienen eventos. El problema es que cuando un tipo X se suscribe a eventos de otro tipo Y, X ahora tiene una referencia a Y. Esta referencia va a prevenir Y, de ser recogidos.

Yo no entiendo cómo X hará referencia a la Y ???

He modificado un poco mi ejemplo para ilustrar mi caso más de cerca:

class Service //Let's say it's windows service that must be 24/7 online
{       
    A _a;

    void Start()
    {
       CustomNotificationSystem.OnEventRaised += new EventHandler(CustomNotificationSystemHandler)
       _a = new A();

       B b1 = new B(_a);
       B b2 = new B(_a);
       C c1 = new C(_a);
       C c2 = new C(_a);
    }

    void CustomNotificationSystemHandler(args)
    {

        //_a.Dispose(); ADDED BY **EDIT 2***
        a.Dispose();

        _a = new A();
        /*
        b1,b2,c1,c2 will continue to exists as is, and I know they will now subscribed
        to previous instance of _a, and it's OK by me, BUT in that example, now, nobody
        references the previous instance of _a (b not holds reference to _a) and by my
        theory, previous instance of _a, now may be collected...or I'm missing
        something???
        */
    }

}  

class A : IDisposable
        {
           public event EventHandler EventHappened;
        }

        class B
        {          
           public B(A a) //Class B does not stores reference to a internally.
           {
              a.EventHappened += new EventHandler(this.HandleEventB);
           }

           public void HandleEventB(object sender, EventArgs args)
           {
           }
        }

        class C
        {          
           public C(A a) //Class B not stores reference to a internally.
           {
              a.EventHappened += new EventHandler(this.HandleEventC);
           }

           public void HandleEventC(object sender, EventArgs args)
           {
           }
        }

EDIT 2: OK, ahora está claro, cuando el suscriptor se suscribe a los editores de los eventos, es NO crea una referencia a la editorial en el suscriptor. Sólo la referencia del editor al suscriptor creado (a través de EventHandler)…en este caso cuando publisher recogidos por GC antes de que el suscriptor (los suscriptores de vida es mayor, entonces editores), no hay ningún problema.

PERO…que yo sepa, no se garantiza cuando el GC recogerá el editor así que en teoría, incluso si los suscriptores de la vida es mayor, entonces los editores, puede suceder que el suscriptor es legal para el cobro, pero el editor aún no se recoge (no sé si dentro de catálogo global más cercano ciclo, GC será lo suficientemente inteligente como para recoger editorial y, a continuación, suscriptor.

De todos modos, en este caso, ya que mi suscriptor no tiene referencia directa a la editorial y no puede darse de baja del evento, me gustaría hacer publisher para implementar IDisposable, con el fin de disponer de ella antes de eliminar todas las referencias a él (ver en CustomNotificationSystemHandler en mi ejemplo).

Y otra vez Lo que debo escribir en los editores de método dispose () para borrar todas las referencias a los suscriptores? debe ser EventHappened -= null; o EventHappened = null; o no hay manera de hacerlo de tal manera, y necesito hacer algo, como el de abajo ???

public event EventHandler EventHappened
   {
      add 
      {
         eventTable["EventHappened"] = (EventHandler)eventTable["EventHappened"] + value;
      }
      remove
      {
         eventTable["EventHappened"] = (EventHandler)eventTable["EventHappened"] - value; 
      }
   }
posibles duplicados de Quitar controladores de eliminación de objetos
Esto no es un duplicado de esa pregunta.

OriginalEl autor Alex Dn | 2012-07-16

7 Comentarios

  1. 4

    He añadido Mis comentarios en su código de ejemplo.

    class A : IDisposable
    {
    public event EventHandler EventHappened
    {
    add 
    {
    eventTable["EventHappened"] = (EventHandler)eventTable["EventHappened"] + value;
    }
    remove
    {
    eventTable["EventHappened"] = (EventHandler)eventTable["EventHappened"] - value; 
    }
    }
    public void Dispose()
    {
    //Amit: If you have only one event 'EventHappened', 
    //you can clear up the subscribers as follows
    eventTable["EventHappened"] = null;
    //Amit: EventHappened = null will not work here as it is 
    //just a syntactical sugar to clear the compiler generated backing delegate.
    //Since you have added 'add' and 'remove' there is no compiler generated 
    //delegate to clear
    //
    //Above was just to explain the concept.
    //If eventTable is a dictionary of EventHandlers
    //You can simply call 'clear' on it.
    //This will work even if there are more events like EventHappened          
    }
    }
    class B
    {          
    public B(A a)
    {
    a.EventHappened += new EventHandler(this.HandleEventB);
    //You are absolutely right here.
    //class B does not store any reference to A
    //Subscribing an event does not add any reference to publisher
    //Here all you are doing is calling 'Add' method of 'EventHappened'
    //passing it a delegate which holds a reference to B.
    //Hence there is a path from A to B but not reverse.
    }
    public void HandleEventB(object sender, EventArgs args)
    {
    }
    }
    class C
    {          
    public C(A a)
    {
    a.EventHappened += new EventHandler(this.HandleEventC);
    }
    public void HandleEventC(object sender, EventArgs args)
    {
    }
    }
    class Service
    {       
    A _a;
    void Start()
    {
    CustomNotificationSystem.OnEventRaised += new EventHandler(CustomNotificationSystemHandler)
    _a = new A();
    //Amit:You are right all these do not store any reference to _a
    B b1 = new B(_a);
    B b2 = new B(_a);
    C c1 = new C(_a);
    C c2 = new C(_a);
    }
    void CustomNotificationSystemHandler(args)
    {
    //Amit: You decide that _a has lived its life and must be disposed.
    //Here I assume you want to dispose so that it stops firing its events
    //More on this later
    _a.Dispose();
    //Amit: Now _a points to a brand new A and hence previous instance 
    //is eligible for collection since there are no active references to 
    //previous _a now
    _a = new A();
    }    
    }

    b1,b2,c1,c2 seguirá existe como es, y sé que lo hará ahora
    suscrito a instancia anterior de _a, y está bien por mí, PERO en ese
    ejemplo, ahora, nadie se hace referencia a la instancia anterior de _a b no
    contiene la referencia a _a) y por mi teoría, instancia anterior de _a, ahora
    puede ser recogido…o me estoy perdiendo algo???

    Como se explica a través de mis comentarios en el código anterior, no te estás perdiendo nada aquí 🙂

    PERO…que yo sepa, no se garantiza cuando el GC recogerá la
    editor así que en teoría, incluso si los suscriptores de vida es mayor
    los editores, puede suceder que el suscriptor es legal para el cobro, pero
    editor aún no se recoge (no sé si dentro de catálogo global más cercano
    ciclo, GC será lo suficientemente inteligente como para recoger editorial y, a continuación,
    suscriptor.

    Desde el editor de referencias suscriptor, nunca puede suceder que el suscriptor se convierte en elegible para la colección antes de que el editor, pero a la inversa puede ser cierto. Si el editor se recoge antes de que el suscriptor entonces, como usted dijo, no hay ningún problema. Si el suscriptor pertenece a una menor GC generación de editor desde el editor contiene una referencia al suscriptor, GC va a tratar el suscriptor como alcanzable y no lo cobrará. Si ambos pertenecen a la misma generación, serán recogidos juntos.

    desde mi suscriptor no tiene referencia directa a la editorial y
    no puede darse de baja del evento, me gustaría hacer publicador
    implementar IDisposable

    Contrario a lo que algunos han sugerido, yo recomendaría la aplicación de disponer si en cualquier momento usted está determinista seguro de que el objeto ya no es necesario. Simplemente la actualización de un objeto de referencia no siempre puede llevar a que un objeto deje de publicar eventos.

    Considere el siguiente código:

    class MainClass
    {
    public static Publisher Publisher;
    static void Main()
    {
    Publisher = new Publisher();
    Thread eventThread = new Thread(DoWork);
    eventThread.Start();
    Publisher.StartPublishing(); //Keep on firing events
    }
    static void DoWork()
    {
    var subscriber = new Subscriber();
    subscriber = null; 
    //Subscriber is referenced by publisher's SomeEvent only
    Thread.Sleep(200);
    //We have waited enough, we don't require the Publisher now
    Publisher = null;
    GC.Collect();
    //Even after GC.Collect, publisher is not collected even when we have set Publisher to null
    //This is because 'StartPublishing' method is under execution at this point of time
    //which means it is implicitly reachable from Main Thread's stack (through 'this' pointer)
    //This also means that subscriber remain alive
    //Even when we intended the Publisher to stop publishing, it will keep firing events due to somewhat 'hidden' reference to it from Main Thread!!!!
    }
    }
    internal class Publisher
    {
    public void StartPublishing()
    {
    Thread.Sleep(100);
    InvokeSomeEvent(null);
    Thread.Sleep(100);
    InvokeSomeEvent(null);
    Thread.Sleep(100);
    InvokeSomeEvent(null);
    Thread.Sleep(100);
    InvokeSomeEvent(null);
    }
    public event EventHandler SomeEvent;
    public void InvokeSomeEvent(object e)
    {
    EventHandler handler = SomeEvent;
    if (handler != null)
    {
    handler(this, null);
    }
    }
    ~Publisher()
    {
    Console.WriteLine("I am never Printed");
    }
    }
    internal class Subscriber
    {
    public Subscriber()
    {
    if(MainClass.Publisher != null)
    {
    MainClass.Publisher.SomeEvent += PublisherSomeEvent;
    }
    }
    void PublisherSomeEvent(object sender, EventArgs e)
    {
    if (MainClass.Publisher == null)
    {
    //How can null fire an event!!! Raise Exception
    throw new Exception("Booooooooommmm");
    //But notice 'sender' is not null
    }
    }
    }

    Si ejecuta el código anterior, más a menudo que no, usted recibirá la ‘Booooooooommmm’. Por lo tanto la idea es que el evento editor debe detener el disparo de eventos cuando estamos seguros de que su vida útil es de hasta.

    Esto se puede hacer a través del método Dispose.

    Hay dos maneras de lograr esto:

    1. Establecer un indicador ‘IsDisposed’ y comprobar que antes de despedir a cualquier evento.
    2. Aclarar el caso de los suscriptores de la lista (como se sugiere en mis comentarios en su código).

    Beneficio de 2 es que la liberación de cualquier referencia a los suscriptores, permitiendo que hay de la colección (como he explicado anteriormente, incluso si el editor es la basura, pero pertenece a una mayor generación todavía puede prolongar la colección de menor generación de suscriptores).

    Aunque, sin duda, será muy raro que la experiencia demostró comportamiento debido a la “oculto” de la accesibilidad de la editorial, pero como usted puede ver los beneficios de la 2 son claras y son válidas para todos los publicadores de eventos, especialmente de larga vida (Singleton a nadie!!!). Esta sí es la pena a aplicar Disponer e ir con 2.

    Gracias! Usted ha hecho casi todas las cosas acerca de los eventos clara para mí 🙂 Pero si puedo usar agregar o quitar y administrar controladores en la tabla Hash, ¿cómo puedo aumentar? regularmente me hizo if(evento!=null)evento(..). Cómo “mapa”, el evento de controlador correcto en la tabla de hash?
    EventHandler suscriptores = (EventHandler)eventTable[“EventHappened”]; if(suscriptores != null) suscriptores(este,EventArgs.Vacío);
    Una pequeña corrección, antes de recuperar los suscriptores del diccionario debe comprobar si la clave “EventHappened” existe o no existe. Por el camino hay una ventaja en la gestión de un diccionario de EventHandlers sólo si su clase de exponer un gran número de eventos de los que sólo unos pocos están en espera de ser contratado en cualquier momento (como los controles de formularios windows forms) como dejar que el compilador genere un defecto copia de delegado para cada uno de los eventos podría resultar en desperdicio de memoria para los objetos de la clase, cuando en realidad no necesita todos los que la memoria.

    OriginalEl autor Amit Mittal

  2. 13

    El tiempo de vida del objeto B es mayor que A, por lo que Una puede eliminarse antes

    Parece que estás confundiendo “Eliminación” con “de la Colección”? Eliminar un objeto tiene nada que ver con la memoria o la recolección de basura. Para asegurarse de que todo está claro, vamos a separar los dos escenarios, y, a continuación, voy a pasar a los eventos del final:

    Colección:

    Nada que hagas va a permitir que Un ser recogidos antes de que el padre B. siempre que B es accesible, por lo que es a pesar de que Una es privada, es todavía accesible desde cualquier código dentro de B, y así como siempre que B es accesible, se considera accesible. Esto significa que el recolector de basura no sabe para asegurarse de que haya terminado con él, y nunca va a recoger Una hasta que también es seguro para recoger B. Esto es cierto incluso si usted llamar explícitamente a la GC.Collect() o similares. Siempre que un objeto es accesible, no serán recogidos.

    Disposición:

    Ni siquiera estoy seguro de por qué usted se implementan IDisposable aquí (tiene nada a hacer con la memoria o la recolección de basura), pero me voy a dar el beneficio de la duda por el momento que nosotros simplemente no ver el recurso no administrado.

    Nada le impide Disponer de Un siempre que lo desee. Simplemente llame a una.Dispose(), y se hace. La única manera de que el .Net framework nunca llamar a Dispose() de forma automática al final de using bloque. Dispose() no se llama durante la recolección de basura, a menos que lo haga como parte de la finalizador del objeto (más en los finalizadores en un momento).

    Cuando se implementa IDisposable, usted está enviando un mensaje a los programadores que este tipo (incluso “debe”) serán eliminados de inmediato. Hay dos corregir los patrones para cualquier IDisposable objeto (con dos variaciones en el patrón). El primer patrón es encerrar el propio tipo en un bloque using. Cuando esto no es posible (por ejemplo: código, como la suya, donde el tipo es un miembro de otro tipo), el segundo patrón es que el tipo primario también se debe aplicar IDisposable por lo que puede ser incluido en un bloque using, y es Dispose() se puede llamar a su tipo Dispose(). La variación de estos patrones es el uso de bloques try/finally en lugar de un bloque using, donde llamar a Dispose() en el bloque finally.

    Ahora en los finalizadores. La única vez que usted necesita para implementar un finalizador es para un IDisposable tipo que origina un recurso no administrado. Así, por ejemplo, si el tipo de Una de arriba es solo un ajuste de una clase SqlConnection, no necesita un finalizador porque el finalizador en SqlConnection mismo se encargará de que sea necesaria la limpieza. Pero, si el tipo a aplicar una conexión a un nuevo tipo de motor de base de datos, usted desea un finalizador para hacer seguro sus conexiones se cierran cuando el objeto se recopila. Su tipo B, sin embargo, no se necesita un finalizador, aunque se gestiona/envolturas de su tipo a, debido a que Una se encargará de finalizar las conexiones.

    Eventos:

    Técnicamente, los eventos son todavía código administrado y no necesitan ser eliminados. Sin embargo, hay un problema con los eventos que a veces la gente le gusta usar IDisposable con tipos que tienen eventos. El problema es que cuando un tipo X se suscribe a eventos de otro tipo Y, Y ahora tiene una referencia a X. Esta referencia puede prevenir la X que se recogen. Si usted espera Y tener una vida más larga, a continuación, X, puede ejecutar en problemas aquí, en particular, si Y es muy larga duración con respecto a muchos X que aparecen y desaparecen a lo largo del tiempo.

    Para evitar esto, a veces, los programadores han escriba Y aplicar IDisposable, y el propósito del método Dispose() es para darse de baja en cualquier eventos, de modo que la suscripción de los objetos también pueden ser recogidos. Técnicamente, este no es el propósito de la Dispose() el patrón, pero funciona bastante bien que no voy a discutir sobre ello. Hay dos cosas que usted necesita saber cuando se utiliza este patrón con los eventos:

    1. Usted no necesita un finalizador si esta es la única razón para la implementación de IDisposable
    2. Instancias de su tipo que aún necesita un uso o try/finally bloque, o usted no se ha ganado nada. De lo contrario Dispose() no serán llamados y sus objetos, todavía no se puede recoger.

    En este caso, su escriba Un privado a tipo B, y tan sólo en el tipo B puede suscribirse a los eventos. Desde ‘a’ es un miembro de tipo B, ni es elegible para la recolección de basura hasta que B ya no es accesible, momento en el que ambos dejarán de estar disponibles y la suscripción de evento de referencia no contará. Esto significa que una referencia que se mantiene en B por Un evento no impediría B se recogen. Sin embargo, si el uso de Un tipo en otros lugares, usted todavía puede querer tener Un implementan IDisposable para asegurarse de que sus eventos son de baja. Si lo hace, asegúrese de seguir el patrón entero, de tal manera que las instancias de Una se adjuntan en el uso o bloques try/finally.

    Pensé que si X suscribirse a un evento de Y, Y toma una referencia a X, no viceversa.
    Sí, creo que tengo hacia atrás aquí. Puede que tengas que actualizar, pero voy a tener que esperar la revisión de más ahora hasta que el trabajo se ralentiza… tal vez tarde esta noche.
    Y si publica un evento, y X se suscribe a ese evento, Y obtiene una referencia a X (a través de la MulticastDelegate detrás). Pero sin tener una referencia Y, ¿cómo se puede X suscribirse a Y el evento? Estoy haciendo ningún error estúpido aquí?
    ver en mi pregunta de edición. X recibidas Y en el constructor, se suscribe Y del evento y, a continuación, simplemente no almacenar referencia Y de forma interna.

    OriginalEl autor Joel Coehoorn

  3. 3

    Contrario a lo que algunas otras respuestas reclamación, eventos cuyo editor del GC vida puede exceder de un suscriptor de la vida útil, debe ser considerado como recursos no administrados. El término “no administrado” en la frase “recurso no administrado” no significa “completamente fuera del mundo de código administrado”, sino más bien se refiere a si los objetos requieren limpieza allá de la proporcionada por el administrado recolector de basura.

    Por ejemplo, una colección puede exponer a un CollectionChanged evento. Si los objetos de algún otro tipo, que se suscribe a un evento repetidamente se creó y abandonados, la colección puede terminar la celebración de un delegado de referencia para cada objeto. Si tales creación y el abandono ocurre por ejemplo, una vez por segundo (lo que podría suceder si el objeto en cuestión fueron creados en una rutina que las actualizaciones de la interfaz de usuario de la ventana) el número de referencias podría crecer en más de 86,000 por cada día que el programa se estaba ejecutando. No es un gran problema para un programa que nunca se ejecuta durante más de un par de minutos, pero un absoluto asesino para un programa que se puede ejecutar durante semanas a la vez.

    Que es realmente lamentable que Microsoft no vino con un mejor evento de limpieza de patrón en vb.net o C#. Hay raramente alguna razón por la que una instancia de una clase que se suscribe a eventos no se limpian antes de que sea abandonado, pero Microsoft no hizo nada para facilitar dicha limpieza. En la práctica, uno puede conseguir lejos con el abandono de los objetos que están suscritos a los eventos con bastante frecuencia (debido a que el evento editorial se salen de su ámbito al mismo tiempo en que el suscriptor) que el molesto nivel de esfuerzo necesario para los eventos de obtener correctamente limpiar no parece que vale la pena. Por desgracia, no siempre es fácil predecir todos los casos en los que un evento de que el editor puede vivir más de lo esperado; si muchas clases de salir de eventos colgando, es posible que grandes cantidades de memoria para ser morosos, porque una de las suscripciones de eventos pasa a pertenecer a un objeto duradero.

    Apéndice en respuesta a editar

    Si X fueron para suscribirse a un evento de Y y, a continuación, abandonar todas las referencias a Y, y si Y se convirtió en elegible para la colección, X no impediría Y de ser recogidos. Eso sería una buena cosa. Si X iban a mantener una fuerte referencia a Y, con la finalidad de poder disponer de ella, de referencia impediría Y de ser recogidos. Que se puede alegar que no ser una buena cosa. En algunas situaciones, sería mejor para X para mantener una larga WeakReference (uno construido con el segundo conjunto de parámetros para true) a Y en lugar de una referencia directa; si el objetivo de la WeakReference no es null cuando X es Disposed, va a tener que darse de baja de Y‘s evento. Si el objetivo es nulo, no puede darse de baja, pero no importa, porque por entonces Y (y su referencia a X) tendrá completamente dejado de existir. Tenga en cuenta que en el improbable caso de que Y muere y es resucitado, X todavía quieren darse de baja de su evento; la utilización de un largo WeakReference se asegurará de que todavía puede suceder.

    Mientras que algunos podrían argumentar que X no debería molestar a mantener una referencia a Y, y Y simplemente debe ser por escrito para el uso de algún tipo de débil caso de envío, tal comportamiento no es correcto en el caso general, porque no hay manera de que Y decir si X haría cualquier cosa que otros código de la atención sobre el incluso si Y es la única referencia a X. Es enteramente posible que X puede contener una referencia a algunos fuertemente arraigada objeto, y podría hacer algo para que otro objeto dentro de su controlador de eventos. El hecho de que Y es la única referencia a X no debe implicar que no hay otros objetos son “interesados” en X. El general-solución correcta es la que tienen los objetos que no están interesados en otros objetos a los eventos de notificar el último de los objetos de ese hecho.

    OriginalEl autor supercat

  4. 1

    Me gustaría tener mi clase B implementa IDisposable y es deshacerse de la rutina, me gustaría, en primer lugar comprobar si a es no nulo y, a continuación, disponer A. mediante este enfoque sólo tienen que asegurarse de disponer de la última de su clase y la interna se encargará de todas las otras disponer.

    OriginalEl autor Azhar Khorasany

  5. 0

    No necesidad para desenganchar los controladores de eventos cuando la eliminación de un objeto, aunque puede quiere. Por eso me refiero a que la GC va a limpiar los controladores de eventos igual de bien, sin ninguna intervención de su parte, sin embargo, dependiendo de la situación puede que desee quitar los controladores de eventos antes de la GC hace con el fin de evitar que el controlador se llama cuando no se lo esperan.

    En su ejemplo, creo que tienes tus papeles a la inversa – clase A no debe ser la suscripción a los controladores de eventos añadidos por otras personas y no tiene ninguna necesidad real para quitar los controladores de eventos eiether, como se puede en lugar de simplemente dejar de subir esos eventos!

    Supongamos sin embargo que la situación se invierte,

    class A
    {
    public EventHandler EventHappened;
    }
    class B : IDisposable
    {
    A _a;
    private bool disposed;
    public B(A a)
    {
    _a = a;
    a.EventHappened += this.HandleEvent;
    }
    public void Dispose(bool disposing)
    {
    //As an aside - if disposing is false then we are being called during 
    //finalization and so cannot safely reference _a as it may have already 
    //been GCd
    //In this situation we dont to remove the handler anyway as its about
    //to be cleaned up by the GC anyway
    if (disposing)
    {
    //You may wish to unsubscribe from events here
    _a.EventHappened -= this.HandleEvent;
    disposed = true;
    }
    }
    public void HandleEvent(object sender, EventArgs args)
    {
    if (disposed)
    {
    throw new ObjectDisposedException();
    }
    }
    }

    Si es posible para A continuar la recaudación de eventos, incluso después de B ha sido eliminado, y el controlador de eventos para B podría hacer algo que puede causar una excepción o algún otro comportamiento inesperado si B está dispuesto a continuación, es probablemente una buena idea para darse de baja de este evento de primera.

    No, no me han cambiado de rollos, he modificado mi pregunta para ser más claros.

    OriginalEl autor Justin

  6. 0

    Referencia de MSDN

    “Para evitar que el controlador de eventos que se invoca cuando se produce el evento, darse de baja en el evento. Con el fin de prevenir pérdidas de recursos, debe darse de baja de los eventos antes de eliminar un objeto de suscriptor. Hasta que te des de baja de un evento, el delegado de multidifusión que subyace en el evento en que el objeto de publicación tiene una referencia al delegado que encapsula el controlador de eventos del suscriptor. Mientras el objeto de publicación sostiene que la referencia, la recolección de basura no va a eliminar tu suscriptor objeto.”

    “Cuando todos los suscriptores han cancelado la suscripción a un evento, el evento instancia en la clase de editor se establece en null.”

    El problema es que yo no estoy desechar el suscriptor, me desechar el editor (suscriptor siguen existiendo), además del suscriptor no tiene referencia a la editorial internamente.

    OriginalEl autor bluelightning1

  7. 0

    El objeto de referencias B a través de delegado EventHandler(Una tiene una instancia de EventHandler que las referencias B). B no tiene ninguna referencia a A. Cuando se establece en null será recopilada y la memoria se libera.
    Así que no es necesario borrar nada en este caso.

    OriginalEl autor Radin Gospodinov

Dejar respuesta

Please enter your comment!
Please enter your name here