Is there reason why you can't declare a static variable within a C# method?
过去几年我一直在C语言中工作,并且我设法习惯将单用途的static变量放在我代码中使用它们的位置附近。
当编写一个非常基本的方法,需要一个方法范围的静态值时,我有点惊讶地发现编译器不喜欢我试图从我的方法中定义一个静态对象。
谷歌已经证实这在C内是不可能的。不过,我很好奇为什么代码,像下面这样,是完全禁止的。
1 2 3 4 5
| public int incrementCounterAndReturn()
{
static int i = 0;
return ++i;
} |
当然,这是一个简单化的例子,可以为同样的影响重新定义,但这并不重要。方法范围、静态值都有它们的位置和用途。哪些设计决策阻止了C_内静态对象的实现?
我们的版本是5.0,现在是2013年。我只能假设这是不可能的,因为设计选择,而不仅仅是因为"这是复杂和难以实现的东西。"有人有任何内幕信息吗?
- "可能重复":stackoverflow.com/questions/10795502/…
- 我不知道他们为什么没有在C中实现这一点。我个人认为这是一个糟糕的实践,至少对于我正在考虑的用例来说是这样。
- 只需在vb.net中编写此代码。看看生成的IL。是的,当多个线程可以调用此方法时,确保变量只初始化一次是非常昂贵的。隐藏大量代码不是C方式。也不是vb.net的方式,但他们没有选择。而不是C的方式,它只是让你的腿射下来。
- 谢谢@hanspasant。我应该考虑一下!
- 一个相关的、更流行的特性请求:属性支持值范围。
语言设计团队不需要提供不实现功能的原因。相反,需要这个特性的人来证明这个特性是设计、实现、测试和教育团队花费预算的最佳可能方式。没有人能成功地为您所建议的功能做到这一点。
如果我仍然是设计团队的成员,并且有了这个特性,我会指出这是完全不必要的。C中的特性是造成开发人员混乱的一个已知原因,特别是对于新手来说,本地vs类型范围的好处很小。
- 谢谢埃里克!你是对的,没有必要说为什么你没有把某些东西实现成一种语言。尽管如此,我还是很好奇,这是否是一个特定的选择,作为避免做的事情,或者如果这是一个没有做的事情,因为这将是大量的工作,几乎没有(或没有)好处。再次感谢。这就是我要找的。
- 我添加了一些文字来表达你的意见。
基础运行时不提供方法级静态变量。在CLR中,所有"静态"数据都是在类型级别上定义的,而不是方法级别。C决定不在其语言设计中的语言级别添加这一点。
这纯粹是一种设计选择。vb.net编译到同一个il,它允许通过函数或子语句中的shared关键字来实现这一点(尽管它是通过编译器"提升"变量为类级静态变量来处理的)。
- 我主要是C,但对VB如何处理这个很好奇。如果用相同名称的不同方法声明两个静态方法级变量,vb copmpiler会做什么?给他们化名?你必须用TypeName.Alias访问它们吗?或者只能从方法中访问它们?
- @Charlesbretana它会修改变量的名称,类似于C中汽车属性的后备存储。"real"名称(就clr而言)不是用户键入的名称。
- 我忘记了Shared关键字(我已经很久没有写过任何形式的vb了),我理解静态是如何在c中工作的。不过,如果你想实现这一点,我想可以做到。我不认为这很容易,但是,正如我所说的,我不认为这会如此困难以至于在超过10年的.NET中,它从来没有被添加为一个特性。我想没有足够的干草叉…
- @Reed,然后我想您不能从类型名访问它们,只能从使用用户指定的名称声明它们的方法中访问它们?
- @如果语言团队认为这是有必要的话,可以很容易地添加它。这很容易解决(通过自己在类级别声明),所以这样做几乎没有意义。
- @是的-它们只能在该方法中访问,而不能在类中的其他地方访问。(当然,您可以使用反射来"查找"和获取变量,因为它实际上是运行时中的私有类级静态变量…)
- @RLH在这里查看Eric Lippert的答案:stackoverflow.com/a/2806990/65358它与"为什么不这样做"相关(对于任何C功能)。
- 是的,我想要的是Reedcopsey所说的类似于VB实现的东西。静态变量之所以需要方法作用域,部分原因在于可以为字段使用非常通用的名称(如i),而不用担心它如何影响其他代码。是的,类范围静态仍然可以使用。不过,方法范围仍然有用。我不在乎编译器是否使用了某种形式的魔力,将我的方法static提升为类static,并且方法声明是简单的"语法糖"。从代码上看,影响是一样的。
- @RLH是关于一个不同的特性——但这就是语言团队在一般情况下增加特性的方法。方法级静态是一个类似的东西——它们有一些很好的用例,但是它们也引入了很多复杂性(您如何确定它们何时被初始化)?它们将是底层的静态级数据,但是初始化规则会变得奇怪),而且很容易解决。
- 感谢所有这些细节,里德。我最后可能会给出答案,除非我认为我会让这一个浮动一段时间,以防微软内部人员决定进入并进一步阐述复杂性问题或明确设计出规范之外的原因。
NET框架和语言是围绕这样一个概念设计的:任何将要编译程序集的人都应该被认为是值得信赖的,足以访问其中的所有代码。从语义的角度来看,在方法bar中声明静态变量foo相当于在方法外部声明一个私有静态变量,并在方法内部访问它,前提是只选择一个在其他地方不使用的名称作为名称。如果按约定将方法名和含义(如bar_foo结合起来),通常可以很容易地避免命名冲突。由于语义相当于在方法外部声明变量,因此不需要在方法内部声明变量。
因为在CLR中,静态变量与类型关联。它们的存储与它们关联的类型(类或stuct)相关联。
- 虽然这是真的,但是如果设计者决定这样做的话,语言就可以很容易地解决这个问题。例如,vb可以。
static变量的作用域是类,而不是对象实例。要实现这一点,您的方法必须声明为static,我相信您的类也必须是static(因为实例化不相关)。
但是变量本身必须在类级别声明。C不允许创建方法局部静态变量。
值得注意的是:这种操作使得单元测试方法非常困难。一般情况下,在C中,人们会让普通的阶级持有这种状态;事实上,这正是yieldreturn在幕后工作的方式。
- 我现在不在我的代码前面,但你是说,如果我将一个方法定义为static,我也可以在该方法中定义一个static int?有趣。
- @不,你不能-你仍然需要使静态变量类级别。
- @RLH:不,我错了,我只是试了一下,但IDE不接受。static变量声明必须在类级别完成。