多线程环境中SendOrPostCallback和Action之间的区别?

kri*_*ris 2 c# multithreading dependency-properties begininvoke

我很擅长使用线程.我试图设定一个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));
Run Code Online (Sandbox Code Playgroud)

我意识到在setter中你必须使用SendOrPostCallback(因为它在调用方法时提供了一个参数).它不适用于Action(因为缺少参数.而且,wpf真的是一个关于它的婊子,调试并找到TargetParameterCountException的原因,"没有源可用",根本没有线索.

为什么我必须在那里使用SendOrPostCallback?我怎么知道在这种情况下这是正确的?因为实际上通过以下方式调用setter:

Dispatcher.BeginInvoke((Action)(()=>State=States.Updating), null);
Run Code Online (Sandbox Code Playgroud)

并使用SendOrPostCallback而不是当然导致TargetParameterCountException ..

只是想知道看似不一致的事情是否只是常识?感觉有点迷失在这里,至少自从谷歌搜索SendOrPostCallback,Action和BeginInvoke作为关键字没有有意义的结果.

Ani*_*Ani 7

相关信息:

Dispatcher.BeginInvoke你正在使用的超载是:

public DispatcherOperation BeginInvoke(
    DispatcherPriority priority,
    Delegate method,
    Object arg
)
Run Code Online (Sandbox Code Playgroud)

method:一个带有一个参数的方法的委托,该方法被推送到Dispatcher事件队列.

2. SendOrPostCallBack代表被宣布为:

public delegate void SendOrPostCallback(object state)
Run Code Online (Sandbox Code Playgroud)

3.至于Action:

public delegate void Action()
Run Code Online (Sandbox Code Playgroud)

显然,SendOrPostCallBack委托是兼容的,因为它只需要一个参数但Action不是,因为它是无参数的.

当然,如果您愿意,可以使用Action<T>委托,它只需要一个参数:

Dispatcher.BeginInvoke(DispatcherPriority.Background,
                        new Action<States>(arg => SetValue(StateProperty, arg)),
                        value);
Run Code Online (Sandbox Code Playgroud)

另外,您也可以使用不同的过载Dispatcher.BeginInvoke一个期望的说法,是一个代表类型,它利用参数,并获得C#编译器做肮脏的工作,为您在封闭:

Dispatcher.BeginInvoke(DispatcherPriority.Background,
                        new Action(() => SetValue(StateProperty, value));
Run Code Online (Sandbox Code Playgroud)

请注意,这value是一个捕获的变量,所以请小心.

(此外,此答案不涉及任何线程安全问题,仅涉及涉及的代理签名.)