.NET - Is there any way to create a non-static thread method?
Is there any way to create a non-static thread method at .NET? Show me code please.
开发者_高级运维The following code doesn't work:
ThreadStart ts = delegate { drawFloorAround(); };
public void drawFloorAround() { ... }
Gives this error -> "A field initializer cannot reference the non-static field, method, or property". If I change the method do static, it works. But I don't want to.
... gives this error "A field initializer cannot reference the non-static field, method, or property".
Read the error message more carefully. It is telling you precisely what is wrong. A field initializer cannot reference a non-static method. That's because the compiler is trying to protect you from this bug:
class C
{
int foo;
int bar = GetBar();
public C(int newFoo)
{
this.foo = newFoo;
}
private int GetBar() { return this.foo + 1; }
}
You do "new C(123)". What is bar set to? If this were legal code then it would be set to 1, not 124. Why? Because first foo gets initialized to zero, then GetBar() gets called, then the constructor body sets this.foo to 123.
To prevent this bug it is simply illegal to reference an instance method or field in a field initializer.
Now, you might reasonably point out that in your code, you do not use the instance method, you only reference it. You never actually call it. This actually is safe. However, the rules of C# are designed to be simple and conservative; even though we could prove that this case is safe, we take the conservative, simple path and say that any reference to the instance in a field initializer is illegal.
If I change the method to static, it works.
Correct. In that case, the method does not depend upon instance state which has not yet been set up.
But I don't want to.
OK, then your only other choice is to stop using a field initializer. Put the initialization in the constructor; you then take responsibility for ensuring that the initialization does not accidentally use uninitialized state.
If you mean is it possible to start a thread with a non-static method - i.e. an instance method - then yes it is. But the same rules apply as to calling an instance method directly - you can only do it if you have an instance. For example, if you have an instance in a variable called foo
then you can write this:
ThreadStart ts = delegate { foo.DrawFloorAround(); };
If you don't already have an instance that you can use, then you must first create one:
ThreadStart ts = delegate { new Foo().DrawFloorAround(); };
If you don't want to create an instance then your method probably should be static.
Yes
public class DoSomthing
{
public void Do()
{
Thread t = new Thread(DoInBackground);
t.Start();
}
public void DoInBackground()
{
// ....
}
}
Edit: the problem in the example code is that it is a field initialiser. Move this code to an explicit constructor:
ThreadStart ts;
public TypeName() {//constructor
ts = this.SomeMethod;
}
private void SomeMethod() {....}
Any method can act as a ThreadStart as log ad it takes no args and returns void. IMO the easiest option is a lambda or anon method as this allows closures:
ThreadStart ts = delegate {
someObj.DoSomething(x, y, "z");
};
But for an instance method that returns void and takes no args:
var obj = /* init obj */
ThreadStart ts = obj.SomeMethod;
Then
var thread = new Thread(ts);
Initializers run before constructors, so you have no instance to set it to. Set the value in your constructor and you should be okay.
class DoesNotWork {
public Action ts = Frob; // doesn't work, cannot access non-static method
void Frob() { }
}
class ThisIsFine {
public Action ts;
public ThisIsFine() { ts = Frob; }
void Frob();
}
It's important for anyone moving to C# from vb.net to note that the rules have changed between VB.net and C#. Under the vb.net (IMHO better) rules, initializers run between the call to mybase.new and the following statement of the constructor; it is permissible for field initializers to make reference to fields and properties of the current object. While this can cause problems if done carelessly, it allows variable initialization (and in some cases cleanup) to be handled at the same place in source code as the declaration. Anyone migrating to C# needs to recognize this difference in initializer handling. While it's possible in vb.net to properly dispose an iDisposable which is created in an initializer, that is not possible in C# without a severe kludge using a threadstatic variable.
精彩评论