.NET – 有没有办法创建非静态线程方法?
有没有办法在.NET上创建非静态线程方法? 请给我看代码。
以下代码不起作用:
ThreadStart ts = delegate {drawFloorAround(); };
public void drawFloorAround() { ... }
给出此错误 – >“字段初始值设定项不能引用非静态字段,方法或属性”。 如果我改变方法做静态,它的工作原理。 但我不想。
…给出此错误“字段初始值设定项不能引用非静态字段,方法或属性”。
请仔细阅读错误消息。 它告诉你究竟出了什么问题。 字段初始值设定项不能引用非静态方法 。 那是因为编译器试图保护您免受此错误的影响:
class C { int foo; int bar = GetBar(); public C(int newFoo) { this.foo = newFoo; } private int GetBar() { return this.foo + 1; } }
你做“新C(123)”。 什么是酒吧? 如果这是合法代码,则将其设置为1,而不是124.为什么? 因为第一个foo初始化为零,然后调用GetBar(),然后构造函数体将this.foo设置为123。
为了防止此错误,在字段初始值设定项中引用实例方法或字段是非法的。
现在,您可以合理地指出,在您的代码中,您不使用实例方法,您只需引用它。 你从来没有真正称呼它。 这实际上是安全的。 但是,C#的规则设计简单而保守; 即使我们可以certificate这种情况是安全的,我们采取保守的简单路径,并说在字段初始化程序中对实例的任何引用都是非法的。
如果我将方法更改为静态,它可以工作。
正确。 在这种情况下,该方法不依赖于尚未建立的实例状态。
但我不想。
好的,那么你唯一的另一个选择是停止使用字段初始化程序 。 将初始化放在构造函数中; 然后,您负责确保初始化不会意外使用未初始化状态。
如果你的意思是可以使用非静态方法启动一个线程 – 即一个实例方法 – 那么是的。 但是同样的规则适用于直接调用实例方法 – 只有拥有实例才能执行。 例如,如果您在名为foo
的变量中有一个实例,那么您可以这样写:
ThreadStart ts = delegate { foo.DrawFloorAround(); };
如果您还没有可以使用的实例,则必须先创建一个:
ThreadStart ts = delegate { new Foo().DrawFloorAround(); };
如果您不想创建实例,那么您的方法可能应该是静态的。
是
public class DoSomthing { public void Do() { Thread t = new Thread(DoInBackground); t.Start(); } public void DoInBackground() { // .... } }
编辑:示例代码中的问题是它是字段初始化程序。 将此代码移动到显式构造函数:
ThreadStart ts; public TypeName() {//constructor ts = this.SomeMethod; } private void SomeMethod() {....}
任何方法都可以作为日志广告充当ThreadStart,它不需要args并返回void。 IMO最简单的选择是lambda或anon方法,因为它允许闭包:
ThreadStart ts = delegate { someObj.DoSomething(x, y, "z"); };
但是对于返回void并且不带args的实例方法:
var obj = /* init obj */ ThreadStart ts = obj.SomeMethod;
然后
var thread = new Thread(ts);
初始化程序在构造函数之前运行,因此您没有实例将其设置为。 在构造函数中设置值,你应该没问题。
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(); }
对于从vb.net迁移到C#的任何人来说,重要的是要注意VB.net和C#之间的规则已经发生了变化。 在vb.net(更好的恕我直言)规则下,初始化程序在调用mybase.new和构造函数的以下语句之间运行; 字段初始值设定项允许引用当前对象的字段和属性。 虽然如果不小心这样做会导致问题,但它允许在源代码中与声明相同的地方处理变量初始化(在某些情况下清理)。 迁移到C#的任何人都需要识别初始化程序处理中的这种差异。 虽然在vb.net中可以正确处理在初始化程序中创建的iDisposable,但在没有使用threadstatic变量的严重kludge的情况下,这在C#中是不可能的。