开发者

C# - Send UI reference to Task.Factory.StartNew();?

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*.bloc开发者_StackOverflowkingCollection.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.


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


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜