method - Anular la suscripción del método anónimo en C#
lambda method c# (11)
Dado que la función de funciones locales de C # 7.0 ha sido lanzada, el enfoque suggested por Jc se vuelve realmente claro.
void foo(object s, MyEventArgs ev)
{
Console.WriteLine("I did it!");
MyEvent -= foo;
};
MyEvent += foo;
Entonces, honestamente, no tiene una función anónima como variable aquí. Pero supongo que la motivación para usarlo en su caso puede aplicarse a las funciones locales.
¿Es posible cancelar la suscripción de un método anónimo de un evento?
Si me suscribo a un evento como este:
void MyMethod()
{
Console.WriteLine("I did it!");
}
MyEvent += MyMethod;
Puedo cancelar la suscripción de esta manera:
MyEvent -= MyMethod;
Pero si me suscribo usando un método anónimo:
MyEvent += delegate(){Console.WriteLine("I did it!");};
¿Es posible cancelar la suscripción de este método anónimo? ¿Si es así, cómo?
Desde la memoria, la especificación no garantiza explícitamente el comportamiento de ninguna manera cuando se trata de la equivalencia de delegados creados con métodos anónimos.
Si necesita darse de baja, debe usar un método "normal" o retener al delegado en otro lugar para poder darse de baja exactamente con el mismo delegado que usó para suscribirse.
En 3.0 se puede acortar a:
MyHandler myDelegate = ()=>Console.WriteLine("I did it!");
MyEvent += myDelegate;
...
MyEvent -= myDelegate;
En lugar de mantener una referencia a cualquier delegado, puede instrumentar su clase para devolver a la persona que llama la lista de invocación del evento. Básicamente, puede escribir algo como esto (asumiendo que MyEvent está declarado dentro de MyClass):
public class MyClass
{
public event EventHandler MyEvent;
public IEnumerable<EventHandler> GetMyEventHandlers()
{
return from d in MyEvent.GetInvocationList()
select (EventHandler)d;
}
}
Por lo tanto, puede acceder a la lista completa de invocaciones desde fuera de MyClass y cancelar la suscripción a cualquier controlador que desee. Por ejemplo:
myClass.MyEvent -= myClass.GetMyEventHandlers().Last();
He escrito un post completo sobre esta técnica here .
Si desea poder controlar la desuscripción, debe seguir la ruta indicada en su respuesta aceptada. Sin embargo, si solo le preocupa borrar las referencias cuando su clase de suscripción se sale del alcance, entonces hay otra solución (ligeramente complicada) que implica el uso de referencias débiles. Acabo de publicar una pregunta y respuesta sobre este tema.
Si desea referirse a algún objeto con este delegado, puede usar Delegate.CreateDelegate (Tipo, Objeto objetivo, Método de información de método) .net Considere que el delegado es igual por objetivo y método de información
Si la mejor manera es mantener una referencia en el EventHandler suscrito, esto se puede lograr usando un Diccionario.
En este ejemplo, tengo que usar un método anónimo para incluir el parámetro mergeColumn para un conjunto de DataGridViews.
El uso del método MergeColumn con el parámetro enable establecido en true habilita el evento, mientras que usarlo con false lo inhabilita.
static Dictionary<DataGridView, PaintEventHandler> subscriptions = new Dictionary<DataGridView, PaintEventHandler>();
public static void MergeColumns(this DataGridView dg, bool enable, params ColumnGroup[] mergedColumns) {
if(enable) {
subscriptions[dg] = (s, e) => Dg_Paint(s, e, mergedColumns);
dg.Paint += subscriptions[dg];
}
else {
if(subscriptions.ContainsKey(dg)) {
dg.Paint -= subscriptions[dg];
subscriptions.Remove(dg);
}
}
}
Tipo de enfoque cojo:
public class SomeClass
{
private readonly IList<Action> _eventList = new List<Action>();
...
public event Action OnDoSomething
{
add {
_eventList.Add(value);
}
remove {
_eventList.Remove(value);
}
}
}
- Anular los métodos de agregar / eliminar eventos.
- Mantenga una lista de los controladores de eventos.
- Cuando sea necesario, elimínelos todos y vuelva a agregar los demás.
Esto puede no funcionar o ser el método más eficiente, pero debería hacer el trabajo.
Una solución simple:
simplemente pase la variable eventhandle como parámetro a sí misma. Evento si tiene el caso de que no puede acceder a la variable creada originalmente debido a los subprocesos múltiples, puede usar esto:
MyEventHandler foo = null;
foo = (s, ev, mehi) => MyMethod(s, ev, foo);
MyEvent += foo;
void MyMethod(object s, MyEventArgs ev, MyEventHandler myEventHandlerInstance)
{
MyEvent -= myEventHandlerInstance;
Console.WriteLine("I did it!");
}
Una técnica es declarar una variable para mantener el método anónimo que luego estaría disponible dentro del propio método anónimo. Esto me funcionó porque el comportamiento deseado era darse de baja después de que se manejó el evento.
Ejemplo:
MyEventHandler foo = null;
foo = delegate(object s, MyEventArgs ev)
{
Console.WriteLine("I did it!");
MyEvent -= foo;
};
MyEvent += foo;
Action myDelegate = delegate(){Console.WriteLine("I did it!");};
MyEvent += myDelegate;
// .... later
MyEvent -= myDelegate;
Solo mantén una referencia al delegado alrededor.