public event Action<GameObject> SelectCallbackMethods;
void Start()
{
SelectCallbackMethods += (obj) => CharacterController.Instance.SelectObj(obj.gameObject);
}
void OnMouseUp()
{
SelectCallbackMethods.Invoke(this.gameObject);
SelectCallbackMethods -= (obj) => CharacterController.Instance.SelectObj(obj.gameObject);
}
Как в такой ситуации можно отписать метод? Отписка, используя (-=) после Invoke не работает, метод все равно вызывается.
Правильный ли это подход использования ивентов? Нашел решение: создание переменной для каждого Action, но имеет ли это смысл? Не то же самое ли это, если бы я просто вызывал метод в нужный момент из этого класса:
Action<GameObject> handler;
void Start()
{
handler = (obj) => CharacterController.Instance.SelectObj(obj.gameObject);
SelectCallbackMethods += handler;
}
void OnMouseUp()
{
SelectCallbackMethods.Invoke(this.gameObject);
SelectCallbackMethods -= handler;
}
Причина такого поведения проста: каждый анонимный метод компилятор разворачивает в отдельный метод.
Т. е. из
using System;
public class Program
{
public event Action<object> MyEvent;
void Start()
{
MyEvent += obj => Console.WriteLine(obj);
}
void OnMouseUp()
{
MyEvent.Invoke(this);
MyEvent -= obj => Console.WriteLine(obj);
}
}
получится примерно следующее
using System;
public class Program
{
private sealed class auxiliaryClass
{
public static readonly auxiliaryClass instance = new auxiliaryClass();
public static Action<object> method1;
public static Action<object> method2;
internal void method1_Start(object obj)
{
Console.WriteLine(obj);
}
internal void method2_OnMouseUp(object obj)
{
Console.WriteLine(obj);
}
}
public event Action<object> MyEvent;
private void Start()
{
MyEvent += method1 ?? (method1 = auxiliaryClass.method1_Start);
}
private void OnMouseUp()
{
this.m_MyEvent(this);
MyEvent -= method2 ?? (method2 = auxiliaryClass.method2_OnMouseUp);
}
}
я опустил несущественные в данном вопросе детали, дословный код можно увидеть здесь
Соответственно, при отписке от события, method2
в нем не будет найден и это просто проигнорируется, method1
так и останется в числе подписчиков.
Чтобы решить эту проблему вам нужно явно вынести обработчик в отдельный метод:
using System;
public class Program
{
public event Action<object> MyEvent;
void Start()
{
MyEvent += MyAction;
}
void OnMouseUp()
{
MyEvent.Invoke(this);
MyEvent -= MyAction;
}
void MyAction(object obj) => Console.WriteLine(obj);
}
демонстрация
Ну или переписать код вообще без использования события, например, с простым bool-флагом:
using System;
public class Program
{
public event Action<object> MyEvent;
bool handled;
void Start()
{
handled = false;
}
void OnMouseUp()
{
if (handled) return;
handled = true;
MyAction(this);
}
void MyAction(object obj) => Console.WriteLine(obj);
}
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Нужно объединить статистику из двух таблиц с группировкой по дням (day)p1, p2 - разделы сайта, здесь только для наглядности