在C#方法中声明静态变量的原因是什么?

5
我过去几年一直在从事C语言的工作,我已经习惯了在代码中将单一用途的static变量放在使用它们的附近。
当我编写一个非常基本的需要方法范围静态值的方法时,我有点惊讶地发现编译器不喜欢我尝试从方法内部定义静态对象。
经过谷歌搜索,证明这在C#中是不可能的。尽管如此,我仍然好奇为什么像下面这样的代码完全被禁止。
public int incrementCounterAndReturn()
{
    static int i = 0;
    return ++i;
}

诚然,这只是一个可以重新定义实现相同效果的简单示例,但这并不重要。方法作用域内的静态值有其存在和目的。是什么设计决策阻止了在 C# 中实现静态对象?

我们使用的是 C# 5.0 版本,现在是2013年。我只能假设这不可能是因为“那太复杂和难以实现了”,而是出于设计选择。是否有任何内部信息可提供?


可能是重复问题:https://dev59.com/HGgv5IYBdhLWcg3wKtzj - user1193035
我不知道为什么他们没有在C#中实现这个功能。就我个人而言,至少对于我所考虑的用例来说,我认为这是一种不好的做法。 - JosephHirn
3
只需在VB.NET中编写此代码,并查看生成的IL。确保变量仅在多个线程可以调用此方法时初始化一次是非常昂贵的。隐藏大量代码并不是C#的做法,VB.NET也不是,但他们别无选择。这也不是C的方式,它只会让你开枪打自己的腿。 - Hans Passant
谢谢@HansPassant。我应该考虑到这一点! - RLH
一个相关的、更受欢迎的功能请求: 属性支持值范围 - Brian
5个回答

9
语言设计团队不需要提供不实现某个功能的理由。相反,希望实现该功能的人需要证明该功能是设计、实现、测试和教育团队可以花费预算的最佳方式。迄今为止,没有人成功地做到了这一点。
如果我仍然在设计团队并且有人提出了这个功能,我会指出它是完全不必要的。在C语言中,这个功能已经被证明会导致开发者混淆,特别是对于新手来说,而本地作用域与类型作用域之间的好处微乎其微。

谢谢Eric!你说得对,没有必要解释为什么没有将某些东西实现到语言中。不过,我很好奇这是否是一种特定的选择,以避免做某些事情,还是因为这需要大量工作,而且收益微乎其微(甚至没有)。再次感谢。这就是我想要的答案。 - RLH
我已添加了一些文本来回应你的评论。 - Eric Lippert

3
底层运行时不提供方法级静态变量。在CLR中,“静态”数据都是在类型级别而不是方法级别上定义的。C#决定在语言设计中不添加此功能。
这纯粹是一种设计选择。VB.Net编译成相同的IL,通过Function或Sub声明中的Shared关键字允许此操作(尽管它是通过编译器将变量“提升”为类级别的静态变量来处理的)。

1
我主要使用C#,但是对VB如何处理这个问题很好奇。如果你在不同的方法中声明了两个具有相同名称的静态方法级变量,VB编译器会怎么做呢?给它们起别名吗?你必须使用TypeName.Alias来访问它们吗?还是它们只能在方法内部访问? - Charles Bretana
1
它会破坏变量的名称,类似于C#中自动属性的后备存储所发生的情况。就CLR而言,“真实”的名称并不是用户键入的名称。 - Reed Copsey
@Reed,然后我想你不能从类型名称访问它们,只能从声明它们的方法中使用用户指定的名称访问它们? - Charles Bretana
3
如果语言团队认为有必要,这很容易添加。但是,通过自己在类级别声明可以轻松解决这个问题,所以没有必要这样做。 - Reed Copsey
1
@RLH 在这里查看Eric Lippert的答案:https://dev59.com/LnE85IYBdhLWcg3wYSZk#2806990 这与“为什么不这样做”(对于任何C#功能)有关。 - Reed Copsey
显示剩余5条评论

1
.NET框架和语言的设计理念是,任何要编译程序集的人都应该被认为有足够的信任来访问其中的所有代码。从语义角度来看,在方法bar中声明静态变量foo与在方法外部声明私有静态变量并在方法内部访问它是等效的,前提是选择一个没有在其他地方使用过的名称。如果按照惯例将方法名称和含义组合在一起(例如bar_foo),通常可以很容易地避免命名冲突。由于语义相当于在方法外部声明变量,因此没有必要在内部声明它。

1
static变量作用域是类级别的,而不是对象实例级别的。为了使其起作用,你的方法必须被声明为static,而且我认为你的类也必须是static(因为实例化无关紧要)。
但是变量本身必须在类级别上声明。C#不允许您创建方法局部的静态变量。
值得注意的是:这些操作使得对方法进行单元测试非常困难。通常在C#中,您会创建一个普通类来保存这样的状态;事实上,这正是yieldreturn背后运作的方式

我现在不在我的代码面前,但是你的意思是如果我将一个方法定义为“static”,那么我也可以在方法内定义一个“static int”吗?有趣。 - RLH
1
@RLH 不行,你还需要将静态变量定义在类级别。 - Reed Copsey
@RLH: 不,我错了;我刚试过了,IDE不会接受它。 static变量声明必须在类级别上完成。 - Robert Harvey

1
因为在CLR中,静态变量与类型相关联。它们的存储与它们关联的类型(类或结构)绑定。

虽然这是真的,但如果设计师决定这样做,语言很容易解决它。例如,VB就可以做到。 - Reed Copsey

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