Выполнить метод / установить свойство в определенном потоке

#c# #.net #multithreading #invoke

#c# #.net #многопоточность #вызвать

Вопрос:

Всем привет, я новичок во всей этой многопоточности, поэтому, пожалуйста, извините меня, если я плохо объясню это 🙂

Допустим, у меня есть два класса:

 class abc {
    public string SomeProperty {
        get { return something; }
        set { /* This code has to execute in the main application thread */ }
    }

    public void SomeMethod() {
        /* This code also has to execute in the main application thread */
    }
}

class def {
    abc obj;

    public def() {
        abc = new obj();
    }

    public void SomeMethod() {
        abc.SomeProperty = "SomeValue";
        abc.SomeMethod();
    }
}
  

Проблема, с которой я сталкиваюсь, заключается в получении SomeProperty и someMethod для выполнения в основном потоке приложения. Я пытался:

 abc.GetType().InvokeMember("SomeProperty", System.Reflection.BindingFlags.SetProperty, null, abc, new object[] { "SomeValue" });
abc.GetType().InvokeMember("SomeMethod", System.Reflection.BindingFlags.InvokeMethod, null, abc, null);
  

Однако код, который должен выполняться в основном потоке приложения, не выполняется в основном потоке приложения, даже с использованием InvokeMember (я так все равно не думаю)
Я пробовал выводить текущее имя потока в коде, и оно не выводит имя основного потока приложения.

Есть ли способ, которым я могу это сделать? Если я что-то плохо объяснил, просто дайте мне знать 🙂 Спасибо!

Комментарии:

1. Пожалуйста, объясните, почему вам нужно выполнить этот код в основном (или любом другом) потоке. Ваш подход с использованием InvokeMember просто неверен, и без уточнения ваших намерений вы не можете ожидать действительно полезного ответа, который будет соответствовать вашему реальному случаю.

2. И, пожалуйста, укажите WinForms или WPF

3. Извините за недостаток информации. Это не WinForms или WPF, это консольное приложение. Существует множество причин, по которым это должно выполняться в главном потоке, одна из которых заключается в том, что я создаю приложение, которое использует сетевую библиотеку Лидгрена, и я могу отправлять сетевые сообщения только в том потоке, который прослушивает библиотека.

Ответ №1:

Существуют различные способы сделать это, но мой предпочтительный подход заключается в следующем:

    protected void setTransactionButton(Boolean enabled)
    {
        (new Task(() =>
        {
            transcriptQuitButton.Enabled = enabled;
        })).Start(uiScheduler);
    }
  

В моем коде инициализации я вызвал это:

 uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
  

Что это делает, так это то, что событие происходит в потоке пользовательского интерфейса и избавляет от необходимости BeginInvoke .

Есть разные места, где вы можете найти для BeginInvoke , но если вы можете использовать анонимные функции, и одна статья об этом находится здесь:

http://visualstudiomagazine.com/articles/2009/02/01/use-lambda-expressions-for-abstract-delegates.aspx

Ответ №2:

InvokeMember это просто способ выполнения элемента с использованием отражения. Это не имеет ничего общего с обработкой потоков.

Я подозреваю, что вы действительно ищете Control.Invoke or Dispatcher.Invoke (или неблокирующие BeginInvoke эквиваленты).

Вам, конечно, понадобится ссылка на соответствующий элемент управления или диспетчер, а затем создайте соответствующий делегат для выполнения в другом потоке. Если вы поищете руководство по многопоточности Windows Forms (или WPF), вы должны найти множество примеров. (Мое сетевое подключение на данный момент бесполезно, иначе я бы нашел для вас подходящее.)

РЕДАКТИРОВАТЬ: Теперь, когда вы ясно дали понять, что это консольное приложение, вам придется разработать какую-то форму отправки сообщений. Если поток каким-то образом не прослушивает сообщения, нет способа заставить его выполнить еще один бит кода. Я не использовал библиотеку, о которой вы говорили, но если это вынуждает вас выполнять код в определенном потоке, то она должна предоставлять некоторый эквивалент Control.Invoke и т.д.

Комментарии:

1. Здесь немного запутался. Я не думаю, что смогу использовать Control. Вызывается, потому что это не связано с System. Windows. Формирует объекты. Могу ли я использовать BeginInvoke, это выполнит его в нужном мне потоке? Или я должен исследовать этот диспетчер. Вызвать вещь?

2. @Jamie: Вы не предоставили нам достаточно информации о контексте. Какого рода приложение вы пишете? Вы говорите о «главном потоке приложения» — но этот поток должен будет запускать перекачку сообщений или что-то подобное, если вы собираетесь попросить его выполнить произвольный код.

3. Я изучаю BeginInvoke и думаю, что это именно то, что мне нужно. Возможно ли получить доступ к делегату из MethodInfo, для которого я могу вызвать BeginInvoke? У меня очень большое количество методов, и я действительно не хочу проходить через каждый из них и создавать делегат для них. Спасибо

4. @Jamie: Нет, вы не хотите вызывать BeginInvoke для делегата. Вы хотите передать делегат в BeginInvoke. И вам следует взглянуть на делегирование. CreateDelegate для создания делегата из MethodInfo.

5. О, я только что нашел статью о MSDN. Будет ли диспетчер. BeginInvoke(delegateobj и т.д.) Работает?