разница между SendOrPostCallback и Action в многопоточной среде? - PullRequest
2 голосов
/ 30 ноября 2010

Я довольно новичок в работе с потоками. Я пытался установить значение DependencyProperty:

    public States State
    {
        get { return (States)GetValue(StateProperty); }
        set
        {
            Dispatcher.BeginInvoke(DispatcherPriority.Background,
                //(SendOrPostCallback)delegate { SetValue(StateProperty, value); }, //works
                (Action)(()=> SetValue(StateProperty, value)), //doesnt
                value);
        }
    }
    public static readonly DependencyProperty StateProperty =
        DependencyProperty.Register("State", typeof(States), typeof(FTPDownload), new UIPropertyMetadata(States.Idle));

Я понял, как трудно в установщике использовать SendOrPostCallback (так как он предоставляет аргумент при вызове метода). он НЕ работает с Action (из-за отсутствующего аргумента. И, wpf действительно стервозен по этому поводу, отлаживая и находя причину исключения TargetParameterCountException с «источником недоступен» и вообще без подсказки.

Почему я должен использовать SendOrPostCallback? и как я должен знать, что в этом случае это правильный? Потому что на самом деле вызов сеттера работает через:

Dispatcher.BeginInvoke((Action)(()=>State=States.Updating), null);

и использование SendOrPostCallback вместо курса приводит к TargetParameterCountException ..

Просто задаетесь вопросом, являются ли, казалось бы, непоследовательные вещи подобного рода просто общеизвестным? Чувствуешь себя немного потерянным, по крайней мере, с тех пор, как гуглил с SendOrPostCallback, Action и BeginInvoke как ключевые слова не дали значимых результатов.

1 Ответ

7 голосов
/ 30 ноября 2010

Соответствующая информация:

1. Перегрузка Dispatcher.BeginInvoke, которую вы используете:

public DispatcherOperation BeginInvoke(
    DispatcherPriority priority,
    Delegate method,
    Object arg
)

method: делегат метода , который принимает один аргумент , который помещается в очередь событий Dispatcher.

2. Делегат SendOrPostCallBack объявлен как:

public delegate void SendOrPostCallback(object state)

3.Как для Action:

public delegate void Action()

Очевидно, что делегат SendOrPostCallBack совместим, поскольку он принимает один аргумент, а Action - нет, поскольку он не имеет параметров.

Конечно, вы можете использовать делегат Action<T>, который принимает один аргумент, если вы предпочитаете:

Dispatcher.BeginInvoke(DispatcherPriority.Background,
                        new Action<States>(arg => SetValue(StateProperty, arg)),
                        value);

Кроме того, вы можете использовать другую перегрузку из Dispatcher.BeginInvoke, которая ожидает аргумент типа делегата, который принимает no аргументов, и заставить компилятор C # сделать грязная работа для вас в закрытии:

Dispatcher.BeginInvoke(DispatcherPriority.Background,
                        new Action(() => SetValue(StateProperty, value));

Обратите внимание, что value является захваченной переменной, поэтому, пожалуйста, будьте осторожны.

(Кроме того, в этом ответе не рассматриваются какие-либо проблемы безопасности потоков, речь идет только о соответствующих сигнатурах делегатов.)

...