我熟悉C#规范section 5.3,它说在使用前必须分配变量。
在C和非托管C ++中,这是有意义的,因为堆栈没有被清除,并且用于指针的内存位置可能在任何地方(导致难以追踪错误)。
但我的印象是运行时不允许真正的“未分配”值。特别是未初始化的引用类型将始终具有空值,而不是先前调用方法或随机值时遗留的值。
这是正确的,还是我错误地假设这些年来检查无效?你能在C#中使用非真实的变量,或者CLR是否会处理这个变量并且总是设置了一些值。
答案 0 :(得分:61)
我的印象是运行时不允许真正的“未分配”值。特别是未初始化的引用类型将始终具有空值,而不是先前调用方法或随机值所遗留的值。 这是正确的吗?
我注意到目前还没有人回答你的问题。
你实际问的问题的答案是“sorta”。
正如其他人所说,一些变量(数组元素,字段等)被归类为自动“初始分配”为其默认值。 (对于引用类型,它为null,对于数字类型为零,对于bools为false,对于用户定义的结构为自然递归)。
某些变量未归类为初始分配;特别是局部变量最初没有分配。在使用值的所有点上,编译器必须将它们归类为“明确分配”。
那么你的问题实际上是“是一个局部变量,被归类为没有明确分配实际最初分配与字段相同的方式?”问题的答案是是,在实践中,运行时最初会分配所有本地人。
这有几个不错的属性。首先,您可以在调试器中观察它们在第一次分配之前处于默认状态。其次,垃圾收集器不可能被欺骗去取消引用坏指针,因为堆栈上剩下的垃圾现在被视为托管引用。等等。
运行时允许将本地的初始状态保留为可以安全存在的垃圾。但作为一个实现细节,它永远不会选择这样做。它积极地将内存归零为局部变量。
然后,在使用本地人之前必须明确分配的规则的原因是不,以防止您观察本地的垃圾未初始化状态。这已经不可观察了,因为CLR会主动将本地清除为默认值,与字段和数组元素相同。 这在C#中是非法的原因是因为使用未分配的本地很可能是一个错误。我们只是将其视为非法,然后编译器会阻止您遇到这样的错误。
答案 1 :(得分:9)
据我所知,每种类型都有指定的默认值。
根据此文档,类的字段将分配默认值。
http://msdn.microsoft.com/en-us/library/aa645756(v=vs.71).aspx
本文档说明以下内容始终自动分配默认值。
http://msdn.microsoft.com/en-us/library/aa691173(v=vs.71).aspx
此处有关实际默认值的更多信息: http://msdn.microsoft.com/en-us/library/83fhsxwc.aspx
答案 2 :(得分:3)
取决于声明变量的位置。使用默认值自动初始化类中声明的变量。
object o;
void Method()
{
if (o == null)
{
// this will execute
}
}
方法中声明的变量未初始化,但是当首次使用该变量时,编译器会检查以确保它已初始化,因此代码将无法编译。
void Method()
{
object o;
if (o == null) // compile error on this line
{
}
}
答案 3 :(得分:2)
特别是未初始化的引用类型将始终具有空值
我认为你混合了局部变量和成员变量。第5.3节具体讨论了局部变量。与默认的成员变量不同,本地永远不会默认为空值或其他任何内容:它们只需必须才能在首次读取之前进行分配。第5.3节解释了编译器用于确定是否已分配局部变量的规则。
答案 4 :(得分:1)
有三种方法可以为变量分配初始值:
默认情况下 - 如果您声明一个类变量而没有指定初始值,则会发生这种情况(例如),因此初始值为default(type)
,其中type
是您声明的任何类型变量是。
使用初始化程序 - 当您声明具有初始值的变量时会发生这种情况,如int i = 12;
检索其值之前的任何点 - 如果您有一个没有初始值的局部变量,则会发生这种情况(例如)。编译器确保您没有可访问的代码路径,这些路径将在分配变量之前读取变量的值。
编译器在任何时候都不允许您读取尚未初始化的变量的值,因此您不必担心尝试时会发生什么。
答案 5 :(得分:-1)
所有原始数据类型都有默认值,因此无需担心它们。
所有引用类型都初始化为空值,因此如果您保留未初始化的引用类型,然后在该null引用类型上调用某个方法或属性,您将获得需要正常处理的运行时异常。
同样,如果未按如下方式初始化所有Nullable类型,则需要检查它们是否为null或默认值:
int? num = null;
if (num.HasValue == true)
{
System.Console.WriteLine("num = " + num.Value);
}
else
{
System.Console.WriteLine("num = Null");
}
//y is set to zero
int y = num.GetValueOrDefault();
// num.Value throws an InvalidOperationException if num.HasValue is false
try
{
y = num.Value;
}
catch (System.InvalidOperationException e)
{
System.Console.WriteLine(e.Message);
}
但是,如果您将所有变量保留为未初始化,因为编译器不会抱怨,您将不会得到任何complile错误,它只是您需要担心的运行时。