使用成员函数开启线程

3

我最近发现了这样一个代码片段(下面是我检查过并且可行的简化版本):

using System;
using System.Threading;

namespace Rextester
{
    public class Program
    {
        public class Foo
        {
            public Foo()
            {
                thread = new Thread(new ThreadStart(Loop));
            }

            private void Loop()
            {
            }

            private Thread thread;
        }
        public static void Main(string[] args)
        {
            var foo = new Foo();
            Console.WriteLine("How does it work??");
        }
    }
}
为什么这样的代码可以在编译器没有任何投诉的情况下工作?据我所知,线程应该从静态函数开始。(或者无论如何都应该传递对象引用和成员函数)。但是在这里,我只看到了对成员函数的引用。似乎我在c#中错过了一件大事。也许有一种隐式的方法传递“this”引用? 更新:非常感谢。我只想添加这个事实的小补充。事实证明,编译器自动处理委托(传递正确的引用对象和方法)。以下是il代码:
.method public hidebysig specialname rtspecialname 
        instance void  .ctor() cil managed
{
  // Code size       32 (0x20)
  .maxstack  8
  IL_0000:  ldarg.0
  IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
  IL_0006:  nop
  IL_0007:  nop
  IL_0008:  ldarg.0
  IL_0009:  ldarg.0
  IL_000a:  ldftn      instance void Rextester.Program/Foo::Loop()
  IL_0010:  newobj     instance void 
[mscorlib]System.Threading.ThreadStart::.ctor(object,

native int)
  IL_0015:  newobj     instance void 
[mscorlib]System.Threading.Thread::.ctor(class 
[mscorlib]System.Threading.ThreadStart)
  IL_001a:  stfld      class [mscorlib]System.Threading.Thread 
Rextester.Program/Foo::thread
  IL_001f:  ret
} // end of method Foo::.ctor

3
“should be static” 是错误的,只有在静态方法中创建时它才应该是静态的。尝试使用静态构造函数使其成为真实状态。Loop 作为参数是一个 委托(意味着编译器将负责正确地调用它,例如如果它是实例成员,则使用 this ),它不必是静态的。 - Sinatr
1个回答

8
但是我只看到了关于成员函数的简短提及。 文档说明ThreadStart是一个委托。它代表了在线程上执行的方法。
当创建一个托管线程时,该线程上执行的方法由ThreadStart委托表示。

线程应该从静态函数开始。

这并非必须如此。该函数不一定要是静态的。

文档显示了两个示例。使用静态方法和使用实例方法:

class Test
{
    static void Main() 
    {
        // To start a thread using a static thread procedure, use the
        // class name and method name when you create the ThreadStart
        // delegate. Beginning in version 2.0 of the .NET Framework,
        // it is not necessary to create a delegate explicitly. 
        // Specify the name of the method in the Thread constructor, 
        // and the compiler selects the correct delegate. For example:
        //
        // Thread newThread = new Thread(Work.DoWork);
        //
        ThreadStart threadDelegate = new ThreadStart(Work.DoWork);
        Thread newThread = new Thread(threadDelegate);
        newThread.Start();

        // To start a thread using an instance method for the thread 
        // procedure, use the instance variable and method name when 
        // you create the ThreadStart delegate. Beginning in version
        // 2.0 of the .NET Framework, the explicit delegate is not
        // required.
        //
        Work w = new Work();
        w.Data = 42;
        threadDelegate = new ThreadStart(w.DoMoreWork);
        newThread = new Thread(threadDelegate);
        newThread.Start();
    }
}

class Work 
{
    public static void DoWork() 
    {
        Console.WriteLine("Static thread procedure."); 
    }
    public int Data;
    public void DoMoreWork() 
    {
        Console.WriteLine("Instance thread procedure. Data={0}", Data); 
    }
}

编辑:

关于委托类型,文档中说:

委托是一种类型,表示对具有特定参数列表和返回类型的方法的引用。

在这个MSDN上的委托教程中,您可以看到如何使用new关键字实例化它:

实例化委托 一旦声明了委托类型,就必须创建一个委托对象并将其与特定方法相关联。像所有其他对象一样,使用新表达式创建一个新的委托对象。

这意味着,由于LoopThreadStart具有相同的返回类型,即void和相同的参数列表(此处为空),因此您可以使用实例方法Loop的名称来实例化委托。

编辑2:

我只是对不使用引用的成员函数感到困惑。

这是因为您在声明方法的同一类中声明了线程。

也许有隐式传递this引用的方式吗?

在这种情况下,答案是肯定的。如果您在类内调用方法或使用名称作为委托(指向该方法的指针),那么this是隐式的。


哦,非常感谢。我错过了那个文档。我只是对不使用引用调用成员函数感到困惑。 - Alex Aparin
1
@LmTinyToon,不用谢。现在我更好地理解了你的问题“可能有隐式传递此引用的方式吗?”我编辑了我的帖子并添加了信息。答案是肯定的。 - Mong Zhu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,