C# - 将 UI 引用发送到 Task.Factory.StartNew();?

发布于 2024-10-06 10:59:14 字数 817 浏览 0 评论 0原文

您将如何发送/传递对新任务的实例引用?

假设我已经得到了这个:

    public BlockingCollection<string> blockingCollection = new BlockingCollection<string>();
    textBox_txt.Text = "Result: ";
    public Task t = Task.Factory.StartNew(() =>
    {
        foreach (string value in *???1*.blockingCollection.GetConsumingEnumerable())
        {
            *???1*.blockingCollection.Take() 
            [...bla...]
            *???2*.Invoke(new updateTextBox_txtCallback(*???2*.updatetextBox_txt)
                          , new object[] { "THE RESULT!\r\n" });
        }                
    });

我猜在这里的某个地方 StartNew(() => 我必须将引用传递给blockingContent 和textBox。我环顾四周,但是无法弄清楚语法。(这很麻烦)

请帮忙。

[编辑]所以,如果我从任务中调用静态对象,它显然可以工作;但我需要任务来处理实例;和 updateTextBox_txtCallback 调用。

How would you send/pass instance references to a new task?

Let's say I've got this:

    public BlockingCollection<string> blockingCollection = new BlockingCollection<string>();
    textBox_txt.Text = "Result: ";
    public Task t = Task.Factory.StartNew(() =>
    {
        foreach (string value in *???1*.blockingCollection.GetConsumingEnumerable())
        {
            *???1*.blockingCollection.Take() 
            [...bla...]
            *???2*.Invoke(new updateTextBox_txtCallback(*???2*.updatetextBox_txt)
                          , new object[] { "THE RESULT!\r\n" });
        }                
    });

I'm guessing that somewhere in here StartNew(() => I have to pass the references to the blockingContent and to the textBox. I've looked around but couldn't figure out the syntax. (it's quite hairy)

Help, please.

[Edit] So, if I call a static object from withing the Task, it obviously works; but I need the task to work with instances; namely the blockingCollection and the updateTextBox_txtCallback Invoke.

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

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

发布评论

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

评论(2

爱要勇敢去追 2024-10-13 10:59:14

我重现了您的问题,并在下面提供了解决方法。问题是您使用 Task 作为类中的字段,因此它只能引用静态成员,因为在运行构造函数之前尚未构造实例(在初始化类之前调用​​字段初始值设定项)。
来自 C# 规范 (10.5.5.2):

实例的变量初始值设定项
字段无法引用实例
正在被创建。因此,它是一个
引用 this 时出现编译时错误
在变量初始值设定项中,因为它是
变量的编译时错误
引用任何实例的初始化程序
通过简单的名称成为成员。在
示例类 A { int x = 1;整数 y =
x+1; // 错误,参考
this } 变量的实例成员
y 的初始化结果为
编译时错误,因为它
引用实例的成员
正在创建。

基本上你有两个选择:

  1. 在中初始化你的任务变量
    构造函数
  2. 使用方法代替检索

示例:

public class Foo
{
    public string myProperty = "foobar";
    public Task t;

    public Foo()
    {
        t = Task.Factory.StartNew(() =>
        {
            myProperty = "test";

        });
    }

    //THIS won't compile
    //public Task t = Task.Factory.StartNew(() =>
    //{
    //    myProperty = "test";

    //});

    public Task GetTask()
    {
        Task t = Task.Factory.StartNew(() =>
        {
            myProperty = "test";

        });
        return t;
    }
}

I reproduced your problem, with a workaround below. The problem is that you are using the Task as a field in your class so it can only refer to static members, as the instance hasn't been constructed until the constructor is run (the field initializers are called before the class is initialized).
From the C# specification (10.5.5.2):

A variable initializer for an instance
field cannot reference the instance
being created. Thus, it is a
compile-time error to reference this
in a variable initializer, as it is a
compile-time error for a variable
initializer to reference any instance
member through a simple-name. In the
example class A { int x = 1; int y =
x + 1; // Error, reference to
instance member of this } the variable
initializer for y results in a
compile-time error because it
references a member of the instance
being created.

Basically you have two options:

  1. Initialize your Task variable in the
    constructor
  2. Use a method instead for retrieval

Example:

public class Foo
{
    public string myProperty = "foobar";
    public Task t;

    public Foo()
    {
        t = Task.Factory.StartNew(() =>
        {
            myProperty = "test";

        });
    }

    //THIS won't compile
    //public Task t = Task.Factory.StartNew(() =>
    //{
    //    myProperty = "test";

    //});

    public Task GetTask()
    {
        Task t = Task.Factory.StartNew(() =>
        {
            myProperty = "test";

        });
        return t;
    }
}
诗酒趁年少 2024-10-13 10:59:14

您不必传递引用,因为 C# 支持闭包。只需在 StartNew 块中使用保存该引用的变量,就会导致编译器生成代码,将您的引用打包到传递给匿名方法的状态对象中:

textBox_txt.Text = "Result: ";
public Task t = Task.Factory.StartNew(() =>
{
    // use textBox_txt in this block - the compiler
    // will handle the passing of actual reference to the
    // anonymous method for you                
});

我强烈推荐 闭包之美 了解有关此功能的更多信息。

现在,关闭对 UI 元素的引用的值是否是一个好主意是一个完全不同的讨论。

You don't have to pass the reference because C# supports closures. Simply using the variable holding that reference inside your StartNew block will cause the compiler to generate code that packages up you reference into state object that is passed to the anonymous method:

textBox_txt.Text = "Result: ";
public Task t = Task.Factory.StartNew(() =>
{
    // use textBox_txt in this block - the compiler
    // will handle the passing of actual reference to the
    // anonymous method for you                
});

I highly recommend The Beauty of Closures for more information on this feature.

Now whether or not it is a good idea to close over a value that is a reference to a UI element is a completely different discussion.

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