多线程环境下SendOrPostCallback和Action的区别?

发布于 2024-10-04 19:32:30 字数 1156 浏览 6 评论 0原文

我对使用线程还很陌生。我试图设置 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));

我意识到在 setter 中你必须使用 SendOrPostCallback (因为它在调用方法时提供一个参数)。它不能与 Action 一起使用(因为缺少参数。而且,wpf 确实是个混蛋,调试并找到 TargetParameterCountException 的原因,“没有可用的源”,根本没有任何线索。

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

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

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

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

I'm fairly new to working with threads. I was trying to set a DependencyProperty's value:

    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));

I realized the hard way that in the setter you have to use SendOrPostCallback (as it provides an argument when calling the method). it does NOT work with Action (because of the missing argument. And, wpf is really a bitch about it, debugging and finding the cause of the TargetParameterCountException with "no source available" and no clue at all.

Why do I have to use SendOrPostCallback there? and how should I know that in this case this is the right one? Because actually calling the setter works via:

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

and using the SendOrPostCallback instead of course results in a TargetParameterCountException..

Just wondering if seemingly inconsistent thing like that are just common knowledge? Feeling a bit lost here, at least since googling around with SendOrPostCallback, Action and BeginInvoke as keywords had no meaningful results.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

恰似旧人归 2024-10-11 19:32:30

相关信息:

1.Dispatcher 的重载。您正在使用的 BeginInvoke 是:

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

method:一个方法的委托需要一个参数,该方法被推送到调度程序事件队列。

2.SendOrPostCallBack< /strong> 委托声明为:

public delegate void SendOrPostCallback(object state)

3.As for < strong>Action

public delegate void Action()

显然,SendOrPostCallBack 委托是兼容的,因为它采用单个参数,但 Action 则不然,因为它是无参数的。

当然,您可以使用Action委托,如果您愿意,它确实采用单个参数:

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

或者,您可以使用 Dispatcher.BeginInvoke 的不同重载,它需要一个采用委托类型的参数没有参数,并让 C# 编译器在闭包中为您完成脏活:

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

请注意,value 是捕获的变量,因此请小心。

(此外,这个答案不处理任何线程安全问题,仅涉及所涉及的委托签名。)

The relevant pieces of information:

1.The overload of Dispatcher.BeginInvoke that you are using is:

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

method: A delegate to a method that takes one argument, which is pushed onto the Dispatcher event queue.

2.The SendOrPostCallBack delegate is declared as:

public delegate void SendOrPostCallback(object state)

3.As for Action:

public delegate void Action()

Clearly, the SendOrPostCallBack delegate is compatible since it takes a single argument but Action is not, since it is parameterless.

Of course, you can use the Action<T> delegate, which does take a single argument, if you prefer:

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

Alternatively, you can use a different overload of Dispatcher.BeginInvoke that expects an argument that is of a delegate-type that takes no arguments, and get the C# compiler to do the dirty work for you in the closure:

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

Notice that value is a captured variable, so please be careful.

(Also, this answer doesn't deal with any thread-safety issues, only about the delegate signatures involved.)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文