Ваш код разбит на две полностью отдельные части, серверную сторону и клиентскую сторону .
|
---------->
HTTP request
|
+--------------+ | +--------------+
| | | | |
| browser | | | web server |
| (JavaScript) | | | (PHP etc.) |
| | | | |
+--------------+ | +--------------+
|
client side | server side
|
<----------
HTML, CSS, JavaScript
|
Обе стороны общаются через HTTP-запросы и ответы. PHP выполняется на сервере и выводит код HTML и, возможно, JavaScript, который отправляется как ответ клиенту, где интерпретируется HTML, и выполняется JavaScript. Когда PHP завершит вывод ответа, сценарий закончится, и на сервере ничего не произойдет, пока не появится новый HTTP-запрос.
Пример кода выполняется следующим образом:
Шаг 1, PHP выполняет весь код между тегами . В результате получилось следующее:
Вызов file_put_contents
не привел ни к чему, он просто написал «+ foo +» в файл. Вызов привел к выводу «42», который теперь находится в том месте, где этот код использовался.
Этот итоговый код HTML / JavaScript теперь отправляется клиенту, где он получает оценку , Вызов alert
работает, а переменная foo
нигде не используется.
Весь PHP-код выполняется на сервере до того, как клиент даже начнет выполнение какого-либо JavaScript. В ответе JavaScript, с которым может взаимодействовать JavaScript, нет кода PHP.
Чтобы вызвать некоторый код PHP, клиент должен будет отправить новый HTTP-запрос на сервер. Это может произойти с использованием одного из трех возможных способов:
Вот более подробный изложение этого метода
Вы также можете использовать JavaScript, чтобы браузер открыл новую страницу с помощью window.location
или отправить форму, подражая возможностям 1 и 2.
Action myDelegate = delegate(){Console.WriteLine("I did it!");};
MyEvent += myDelegate;
// .... later
MyEvent -= myDelegate;
Просто держите ссылку на делегата.
Вид ламельного подхода:
public class SomeClass
{
private readonly IList<Action> _eventList = new List<Action>();
...
public event Action OnDoSomething
{
add {
_eventList.Add(value);
}
remove {
_eventList.Remove(value);
}
}
}
Это может не работать или быть наиболее эффективным методом, но должно выполняться.
Если вы хотите контролировать отмену подписки, вам необходимо пройти маршрут, указанный в вашем принятом ответе. Однако, если вы просто обеспокоены очисткой ссылок, когда ваш подписной класс выходит из сферы действия, то есть другое (слегка запутанное) решение, которое предполагает использование слабых ссылок. Я только что опубликовал вопрос и ответ по этой теме.
Вместо того, чтобы ссылаться на любого делегата, вы можете задействовать свой класс, чтобы вернуть список вызовов вызывающему абоненту. В основном вы можете написать что-то вроде этого (предполагая, что MyEvent объявлен внутри MyClass):
public class MyClass
{
public event EventHandler MyEvent;
public IEnumerable<EventHandler> GetMyEventHandlers()
{
return from d in MyEvent.GetInvocationList()
select (EventHandler)d;
}
}
Таким образом, вы можете получить доступ ко всему списку вызовов извне MyClass и отменить подписку на любой обработчик, который вы хотите. Например:
myClass.MyEvent -= myClass.GetMyEventHandlers().Last();
Я написал полный пост об этом tecnique здесь .
Один из способов - объявить переменную для хранения анонимного метода, который затем будет доступен внутри самого анонимного метода. Это работало для меня, потому что желаемое поведение заключалось в том, чтобы отказаться от подписки после обработки события.
Пример:
MyEventHandler foo = null;
foo = delegate(object s, MyEventArgs ev)
{
Console.WriteLine("I did it!");
MyEvent -= foo;
};
MyEvent += foo;
Из памяти спецификация явно не гарантирует поведение в любом случае, когда дело доходит до эквивалентности делегатов, созданных с помощью анонимных методов.
Если вам нужно отказаться от подписки, вы должны либо использовать «нормальный», метод или сохранить делегата где-то в другом месте, чтобы вы могли отказаться от подписки с точно таким же делегатом, которого вы подписали.
Если лучший способ сохранить ссылку на подписанный eventHandler, это может быть достигнуто с помощью словаря.
В этом примере я должен использовать анонимный метод для включения параметра mergeColumn для набор DataGridViews.
Использование метода MergeColumn с параметром enable, установленным в true, позволяет событию при его использовании с false отключает его.
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);
}
}
}
Одно простое решение:
просто передает переменную eventhandle как параметр для себя. Событие, если у вас есть случай, когда вы не можете получить доступ к исходной созданной переменной из-за многопоточности, вы можете использовать это:
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!");
}
MyEvent -= myEventHandlerInstance;
? Если это возможно, у вас будет ошибка. Но я не уверен, что так.
– LuckyLikey
2 June 2016 в 13:27
Поскольку функция C # 7.0 локальных функций была выпущена, подход , предложенный в J c , становится действительно опрятным.
void foo(object s, MyEventArgs ev)
{
Console.WriteLine("I did it!");
MyEvent -= foo;
};
MyEvent += foo;
Итак, честно говоря, у вас нет анонимной функции в качестве переменной здесь. Но я полагаю, что мотивация использовать его в вашем случае может быть применена к локальным функциям.
В версии 3.0 можно сократить до:
MyHandler myDelegate = ()=>Console.WriteLine("I did it!");
MyEvent += myDelegate;
...
MyEvent -= myDelegate;
, если вы хотите обратиться к некоторому объекту с этим делегатом, возможно, вы можете использовать Delegate.CreateDelegate (Тип, Объект target, MethodInfo methodInfo) .net считать, что делегат равен target и methodInfo