【问题标题】:What happens when you call a static method in C#?在 C# 中调用静态方法时会发生什么?
【发布时间】:2011-12-22 15:55:18
【问题描述】:

当您创建一个类的实例时,该实例中的所有变量都特定于该实例,并在该实例超出范围时被终止。但是它在静态方法中是如何工作的呢?假设两个人同时调用 System.Math.Abs​​()。运行时如何区分两个调用者?这是线程进来的地方吗?是否会为每个调用者自动创建单独的线程?

【问题讨论】:

  • this 回答你的问题了吗?
  • .ToString 不是静态方法。
  • Emmanuel,我检查了你提到的帖子。它解决了我的担忧,但没有回答它:(

标签: c# static


【解决方案1】:

当你创建一个类的实例时,当实例超出范围时,所有特定于该实例的变量都会被杀死。

变量——通常称为“字段”,在实例的生命周期之后被释放。 Scope 是程序文本的区域,编译器在该区域中通过名称识别某些内容; lifttime 是存储位置有效的时间部分。范围和生命周期经常混淆。

但是它在静态方法中是如何工作的呢?

静态字段的生命周期是无限的;存储位置是在访问该字段之前的某个时间创建的,并且在 appdomain 被拆除之前不会被销毁。

假设两个人同时调用 System.Math.Abs​​()。

好的。你如何建议发生这种情况?

运行时如何区分两个调用者?这是线程的用武之地吗?

静态方法被编译成一堆机器指令,这些指令是内存中的数字。每个执行线程都有一个与之相关的编号,称为指令指针,它定位当前指令。两个不同的线程可以同时拥有位于同一个静态方法中的指令指针。

是否为每个调用者自动创建单独的线程?

这个问题没有任何意义。如果他们还没有在不同的线程上,您是如何同时获得两个调用者的?

【讨论】:

    【解决方案2】:

    就方法变量的生命周期而言,静态方法和非静态方法之间没有真正的区别。在这两种情况下,作为实现细节,局部变量通常(并非总是:存在异常)分配在堆栈上。堆栈是每个线程的,因此本地方法变量不会在线程之间交叉。

    实例和静态之间的唯一区别这里是实例方法有一个隐式的第零参数,也就是“this”,它是由调用者推送的(加上一些虚拟调度和空值检查的乐趣) .

    为简单起见,我忽略了迭代器块、捕获的变量等。

    【讨论】:

      【解决方案3】:

      一个类的所有静态成员都存在,即使该类的实例不存在。它们在首次使用前的某个时间被初始化,并在程序完成时被清理。

      如果您同时调用一个静态方法,它们将使用该类的任何静态成员的相同副本(如果它们使用它们)。因此,如果静态方法对静态成员(或参数)进行操作,它应该以线程安全的方式进行。如果静态方法只对局部变量进行操作,那么该方法本身通常是线程安全的。

      至于运行时如何区分两个调用者,这是线程的本质。每个线程都有自己的调用堆栈,其中包含任何局部变量、参数、返回地址等的自己的副本。因此这两个调用不会混淆,并且每个调用都正确地返回给它们的调用者。同样,唯一的问题是静态方法是否对非线程安全的静态成员(或非线程安全的参数)进行操作。

      【讨论】:

      • 很好的解释詹姆斯。谢谢。人们怎么知道你刚刚告诉我的?你能推荐一些好书吗,这样的基础知识?
      • 我从 CompSci 编程语言理论课程的学士学位和编程语言的自学中学到了大部分知识。如果您真的想了解细节,请阅读 C# 语言规范,它会告诉您几乎所有关于实现的知识:msdn.microsoft.com/en-us/library/ms228593.aspx
      • 如果你必须推荐本科生的一本书(涉及这样的基础知识),那会是什么?
      • 我本科生的书可悲已经过时了,那是 17 年前 :-) 至于现代书籍,如果你想要好的细节 - 除了基本入门- 尝试“Essential C# 4.0 (3rd Edition)”或“C# in Depth”,但是有很多好书。
      猜你喜欢
      • 2015-04-11
      • 1970-01-01
      • 2014-03-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-02
      • 2022-06-17
      相关资源
      最近更新 更多