У меня есть простой вопрос о делегатах .NET. Скажите, что у меня есть что-то вроде этого:
public void Invoke(Action<T> action)
{
Invoke(() => action(this.Value));
}
public void Invoke(Action action)
{
m_TaskQueue.Enqueue(action);
}
Первая функция включает ссылку на this.Value
. Во время времени выполнения, когда первое, метод с универсальным параметром назовут, он обеспечит this.Value
так или иначе к второму, но как? Они вошли в мой ум:
this.Value
передается, поэтому если m_TaskQueue
выполняет его 5 минут спустя, значение не будет в его недавнем состоянии, это будет тем, чем это было при первой ссылке. Value
будет ссылаться во время выполнения действия, но если я изменяюсь this.Value
к другой ссылке перед выполнением действия это будет все еще указывать на старую ссылкуthis.Value
будет оценен, когда действие назовут. Я полагаю, что фактическая реализация содержала бы ссылку на this
затем оцените Value
на этом во время фактической казни делегата с тех пор нет никакого вызова по имени.Я предполагаю, что это было бы Вызовом стиля имени, но не могло найти документацию настолько задающейся вопросом, если это - четко определенное поведение. Этот класс - что-то как Агент в Scala или Erlang, таким образом, мне нужен он, чтобы быть ориентированным на многопотоковое исполнение. Я не хочу Invoke
функция для разыменования Value
сразу, это будет сделано в безопасном потоке для this
объект m_TaskQueue
.
Vireshark фактически использует Winpcap для этого, и, как показывает другой ответ, вы также можете использовать его.
Можно также использовать класс System.Net.Sockets.Socket
и перевести его в неразборчивый режим. Я использую это для захвата IP-трафика (например, TCP и UDP) из данного сетевого интерфейса. Вот пример.
using System.Net;
using System.Net.Sockets;
Socket socket =
new Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.IP);
socket.Bind(new IPEndPoint(IPAddress.Parse("X.X.X.X"), 0)); // specify IP address
socket.ReceiveBufferSize = 2 * 1024 * 1024; // 2 megabytes
socket.ReceiveTimeout = 500; // half a second
byte[] incoming = BitConverter.GetBytes(1);
byte[] outgoing = BitConverter.GetBytes(1);
socket.IOControl(IOControlCode.ReceiveAll, incoming, outgoing);
После создания и настройки сокета можно использовать метод Receive ()
для начала получения данных. При каждом вызове Receive ()
возвращаемый буфер будет содержать IP-пакет. См. здесь для разбивки заголовка IPv4, здесь для заголовка UDP и здесь для заголовка TCP. Если поле Protocol заголовка IP содержит значение 17, то имеется пакет UDP.
ПРИМЕЧАНИЕ Необработанные сокеты в Windows требуют наличия администратора в локальной системе. Следующий язык содержится в статье MSDN .
-121--2681487-Использование разъема типа SOCK_RAW требует административных привилегий. Пользователи, использующие приложения Winsock которые используют необработанные сокеты, должны быть членами группы администраторов на локальный компьютер, в противном случае необработанный сокет вызовы завершатся неуспешно с кодом ошибки WSAEACCES. В Windows Vista и более поздних версиях доступ для необработанных сокетов применяется в создание сокета. В более ранних версиях Windows, доступ для необработанных сокетов принудительно во время другого сокета операции.
Мои мысли:
Но, как я указал в своем комментарии к посту Андриева выше, это на самом деле делает верхний регистр, который заставляет дисплей располагаться вертикально. Нижний регистр\g не имеет такого эффекта, или если он имеет, то в документации его не упоминается. (У меня нет установки MySQL, которую можно было бы опробовать.)
-121--1607234-Позвольте мне ответить на ваш вопрос, описав, какой код мы на самом деле генерируем для этого. Я переименую ваш запутанно названный другой метод Invoke; нет необходимости понимать, что здесь происходит.
Предположим, что вы сказали
class C<T>
{
public T Value;
public void Invoke(Action<T> action)
{
Frob(() => action(this.Value));
}
public void Frob(Action action)
{ // whatever
}
}
Компилятор генерирует код, как будто вы на самом деле написали:
class C<T>
{
public T Value;
private class CLOSURE
{
public Action<T> ACTION;
public C<T> THIS;
public void METHOD()
{
this.ACTION(this.THIS.Value);
}
}
public void Invoke(Action<T> action)
{
CLOSURE closure = new CLOSURE();
closure.THIS = this;
closure.ACTION = action;
Frob(new Action(closure.METHOD));
}
public void Frob(Action action)
{ // whatever
}
}
Это отвечает на ваш вопрос?
Главное - помнить, что область видимости является лексической; это то, о чем позаботится компилятор. Таким образом, он захватывает переменных , а не их значения . Другой вопрос, являются ли эти значения типами значений или ссылочными типами.
Возможно, вам поможет более экстремальный пример изменения поведения делегата:
var myVariable = "something";
Action a = () => Console.WriteLine(myVariable);
myVariable = "something else entirely"
a();
выводит «что-то совершенно другое». В этом свете не имеет значения, сколько раз вы оборачиваете, сохраняете или перемещаете функцию; он по-прежнему относится к включенной в него переменной. Итак, короче говоря, важно значение заключенной переменной при фактическом выполнении делегата.
Делегат сохраняет ссылку на переменную, а не ее значение. Если вы хотите сохранить текущее значение (при условии, что это тип значения), вам необходимо сделать его локальную копию:
public void Invoke(Action<T> action)
{
var localValue = this.Value;
Invoke(() => action(localValue));
}
Если это изменяемый ссылочный тип, вы можете сделать локальную копию / глубокую копию.