为什么C#没有像C这样的局部静态变量?我很想念!!
为什么C#没有像C这样的局部静态变量?我很想念!!
Answers:
您可以使用委托对其进行仿真...这是我的示例代码:
public Func<int> Increment()
{
int num = 0;
return new Func<int>(() =>
{
return num++;
});
}
您可以这样称呼它:
Func<int> inc = Increment();
inc();
Increment
函数num = 0
。如果将Increment
方法更改为静态,为什么不使用private static num = 0;
?你一无所获。
因为他们搞砸了,却没有适合自己的有用功能。
关于应该如何编码,什么是聪明的东西以及应该重新考虑生活方式的所有争论都是夸张的防御辩解。
当然,C#是纯净的,并且面向whatchamacallit。这就是为什么他们会自动为lambda函数生成持久性本地变量的原因。太复杂了。我好笨
循环作用域静态在许多情况下都是有用且重要的。
简短而真实的答案是,您必须将局部静态变量移入类范围并在C#中承受类名称空间污染。带您去市政厅投诉。
2004年的MSDN博客文章:为什么C#不支持静态方法变量?处理原始帖子中提出的确切问题:
C#没有此功能有两个原因。
首先,通过具有类级别的静态变量,可以获得几乎相同的效果,而添加方法静态变量将需要增加复杂性。
其次,方法级静态变量在重复调用代码或从多个线程调用代码时会引起问题,因此臭名昭著,并且由于定义位于方法中,因此很难找到这些定义。
(Microsoft自己的存档中有相同的博客条目。Archive.org保留了注释。Microsoft的存档中没有。)
状态通常是对象的一部分或类型的一部分,而不是方法的一部分。(当然,例外是捕获的变量。)
如果要等效于局部静态变量,请创建一个实例变量或一个静态变量-并考虑方法本身是否实际上应该是具有该状态的其他类型的一部分。
因此,您想在方法中使用静态局部变量吗?恭喜你!您朝着成为一名真正的程序员又迈出了一步。
不要听所有的人告诉您静态本地人不是“干净”的,它们会阻碍“可读性”,并可能导致细微而难以发现的“错误”。废话!他们只是说,因为他们是想当程序员!他们中的许多人甚至可能在业余时间玩着一种深奥的函数式编程语言。你相信吗?一堆时髦!
真正的程序员拥抱范式我喜欢叫SDD -小号IDE效应d里文d ESIGN。以下是一些最重要的法律:
不可预测!永远不要从方法中两次返回相同的东西-即使使用完全相同的参数调用它!
螺丝的纯度-让我们变脏!状态本质上是渴望改变的,因为它是一类多聚内源性的永不满足的类四面体,即它喜欢被尽可能多的合作者所感动。千万不要错过机会,帮个忙!
当然,在以副作用驱动方式进行编码的工具中,有静态局部变量。但是,正如您所注意到的,C#不支持它们。为什么?因为在过去的二十年中,Microsoft被所谓的Clean Codes所渗透,Clean Coders主张维护性优于灵活性和控制性。您甚至还记得上次看到我们心爱的蓝屏吗?现在猜猜是谁的错!
但是不要害怕!真正的开发人员不必承受那些糟糕的设计决策。如前所述,在lambdas的帮助下,局部变量可能是静态的。
但是,提供的解决方案并不十分令人满意。使用前面的答案,我们几乎符合SDD的代码看起来像这样:
var inc = Increment();
var zero = inc();
var one = inc();
要么
var zero = Increment()();
但这只是愚蠢的。即使是一个崇拜者开发人员可以看到,Increment()
是不正常的方法,将得到可疑。一个真正的程序员,在另一方面,可以使其更加SDD样。他(她)知道,我们可以通过赋予属性类型来使属性或字段看起来像方法Func<T>
!我们只需要通过执行一个lambda来初始化它,该lambda会依次初始化计数器并返回另一个lambda来增加捕获的计数器!
这是正确的SDD代码:
public Func<int> Increment = new Func<Func<int>>(() =>
{
var num = 0;
return () => num++;
}).Invoke();
(您认为上述有点像IIFE吗?是的,您是对的,应该为自己感到羞耻。)
现在,每次调用Increment()
它都会返回不同的结果:
var zero = Increment();
var one = Increment();
当然,您也可以这样做,以使计数器在您的实例的生存期内生存下来。
这会让他们想当程序员!
List<>
,我初始化为的等等null
)。有什么办法可以使它起作用?在Func
总回报率null
,即使我改变在调用方法返回的列表Func
。可以这么说,我以为参考会“坚持”。
Add()
,Remove()
等就可以了。
C#是一种面向组件的语言,没有类或局部方法范围之外的变量概念。方法中的变量也不能声明为静态,因为您可能习惯于在C语言中进行操作。但是,始终可以将类静态变量用作替代变量。
通常,通常有一些方法可以解决C#中的编程问题,而无需使用方法级静态方法。状态通常是应该设计为类和类型的东西,而不是方法。
static object myLock = new object(); lock(myLock){ ... }
从逻辑上讲,是的。它与仅在该方法中使用的类级静态成员相同。但是,方法级静态成员将被更封装。如果存储在成员中的数据仅打算由单个方法使用,则只能由该单个方法访问。
但是,通过创建嵌套类,您可以在C#中获得几乎完全相同的效果。
因为静态局部变量绑定到该方法,并且该方法在所有实例之间共享。
我必须更正自己和其他程序员,他们希望使用该方法在每个类实例中具有唯一性。
但是,如果将其设置为静态类或类的静态实例,则从语法上看,每个容器类是否有一个实例,或者根本没有一个实例。
如果您不使用它们,以后重构也将变得更加容易。
我认为通过为类创建公共静态字段可以轻松解决局部静态的想法。您认为逻辑上的变化很小吗?
如果您认为这将是一个很大的逻辑变化,那么我很想听听如何。
class MyClass
{
public static float MaxDepthInches = 3;
private void PickNose()
{
if (CurrentFingerDepth < MyClass.MaxDepthInches)
{
CurrentFingerDepth++;
}
}
}
我看不到局部静态有什么额外的好处,如果您将类保持单一目的且较小,那么全球静态污染几乎没有问题,因为反对者喜欢抱怨。但是,这只是另一种选择。
using System;
using System.Collections;
public class Program
{
delegate bool DoWork();
public static void Main()
{
DoWork work = Foo().GetEnumerator().MoveNext;
work();
work();
work();
}
public static IEnumerable Foo()
{
int static_x = 10;
/*
do some other static stuff....
*/
main:
//repetative housework
Console.WriteLine(static_x);
static_x++;
yield return true;
goto main;
}
}
您可以使用嵌套类作为解决方法。由于C#将静态变量的范围限制为类,因此可以将嵌套类用作范围。
例如:
public class Foo {
public int Increment() {
return IncrementInternal.Increment();
}
private static class IncrementInternal {
private static int counter = 0;
public static int Increment() {
return counter++;
}
}
}
这里Foo
支持Increment
方法,但是它由IncrementInternal
包含静态变量作为成员的私有嵌套类支持。当然,counter
在的上下文(其他方法)中不可见Foo
。
顺便说一句,如果您想访问Foo
内部的上下文(其他成员和方法)IncrementInternal.Increment
,则可以将其this
作为参数传递IncrementInternal.Increment
给从中调用时Foo
。
为了使范围尽可能小,我的建议是为每个此类方法创建一个嵌套类。而且由于它可能不是很常见,因此嵌套类的数量将保持足够少以保持它的状态。
我认为它比匿名函数或IIFE更干净。
您可以在此处观看现场演示。
如果您可以想象某种形式的Lippert / Farnsworth混合实体向所有人宣布“好消息”!,C#6.0允许使用该using static
语句。这有效地使您可以将静态类方法(似乎还包括属性和成员)导入全局范围。
简而言之,您可以执行以下操作:
using NUnit.Framework;
using static Fizz.Buzz;
class Program
{
[Test]
public void Main()
{
Method();
int z = Z;
object y = Y;
Y = new object();
}
}
namespace Fizz
{
class Buzz
{
public static void Method()
{
}
public static int Z;
public static object Y { get; set; }
}
}
虽然仅在C#6.0中可用,但是据我了解,生成的程序集应该与以前的.NET平台兼容(如果我错了,请更正我)。