C#变量初始化、性能和良好实践

本文关键字:性能 变量 初始化 | 更新日期: 2023-09-27 18:22:22

如果这个线程被认为是主观的,我很抱歉,但我的问题更多地是技术方面的。

我在Framework.Net 4.0中使用C#。我花了几年时间玩C++,我接受的教育是,未初始化的变量会让我大吃一惊。

今天,每当我在C#代码片段中看到一个未初始化的变量时,我都会有点发抖,我真的无法决定是否应该初始化它们。

我读过很多文章,人们说,有些初始化了,有些没有(成员与本地),我读过一些文章,人们认为在C#中初始化vars会给性能带来麻烦。。。

在我当前的应用程序中,我希望有良好的性能,但首先,我需要避免因为变量未初始化而出现愚蠢的错误。

这方面的最佳实践是什么?

编辑:

public MyClass
{
    private int foo; // Is it initialized ? Do I have to ?
    public void MyMethod()
    {
        int bar;  // Is it initialized ? Do I have to ?
        ...
    }
} // Is it a good practice to initialize every vars all the time or not ? 
  // Will I get troubles by not initializing those ?
  // If I do initialize them, will I get performance slowdown ?

C#变量初始化、性能和良好实践

在C#中,您不会像在C/C++中那样遇到未初始化变量具有随机值的问题。

某些变量(例如字段/静态)保证初始化为其默认值(通常为null/0),并且编译器在所有情况下都会给您一个错误,在这些情况下,默认值没有得到保证,并且您在使用前没有手动初始化变量。

换句话说,如果您不确定,请相信编译器会告诉您。

编辑:反之亦然,如果您手动将方法中的局部变量初始化为默认值,并且编译器可以看到您在更改它之前从未使用过它,它将为您删除初始化,因此除非您实际使用该值,否则不会产生开销。

我想知道,如果在C#中,所有变量都是自动的初始化,或者在某些情况下没有

当您声明引用类型变量(如SomeClass的实例)时,它的默认值将是null。一旦您使用新的为变量分配了一些内存,您的变量就会被初始化

SomeClass someClass; //not initialized, it's value is null
someClass = new SomeClass(); //initialized

另一方面,当您声明值类型时,它们会被初始化。例如

int bar; //initialized with value 0

是否始终初始化每个vars是一种好的做法?

好吧,这取决于场景。例如,当您声明布尔时,它的默认值是false。但为了读者的理解,最好明确地做bool myBool = false。另一方面,如果必须将变量作为out传递给某个方法,初始化变量是没有用的,因为它是方法的责任。这实际上取决于你的情景和你喜欢遵循的实践。

如果不初始化这些,我会遇到麻烦吗?

如果您对默认值(未初始化的值)很满意,那么您就不会遇到麻烦。但是,如果您的代码需要一些初始化值,而您的变量没有初始化,那么您可能会遇到麻烦。

如果我真的初始化了它们,我的性能会降低吗?

没有。如果你的应用程序的性能真的很慢,你应该使用一些探查器来找出导致性能慢的原因。初始化变量不太可能导致性能问题

在C#中初始化或不初始化变量取决于您想要实现的目标,这两个选项在不同的情况下都有效。

例如,一个类公开了一些属性,并且您希望这些属性具有默认值:

public class X 
{
    private object _propertyName;
    public object PropertyName
    {
         get { return _propertyName; }
         set 
         {
             _propertyName = value;
             doSomething();
         }
    }
}

在这个类中,如果您试图在设置属性值之前读取该属性的值,那么保持_propertyName未初始化可能会使您暴露于NullReferenceException,因此将其初始化为合适的默认值是很好的做法。

但是,有时您希望为用户提供传入null的选项,在这种情况下,初始化变量可能会覆盖此合法输入。

public void doSomethingToObjectInCollection(object key, List<object> haystack)
{
    // First find it in the collection
    object foundValue;
    for( int i = 0; i < haystack.Count; i++ )
    {
        if( haystack[i].KeyField == key )
            foundValue = key;
    }
    if( foundValue != null )
    {
        // Do something here if there was a foundValue
    }
}

在本例中,将foundValue初始化为默认值将导致不正确的行为。当然,如果很难查看,可以显式地将其初始化为null,但这不会改变代码的行为(与C++不同)。

至于性能方面的考虑,不幸的是,没有"是的,这很糟糕"或"不是,这没关系"的答案。在大多数应用程序中,这可能无关紧要,但如果您有严格的性能要求,那么决定要做什么需要特定于上下文的理解,即在初始化变量时到底发生了什么。

值类型将在分配为零时初始化,但这几乎不是一个昂贵的操作,因此可能不会让您过于担心。

引用类型是指在使用值之前初始化值可能会导致性能下降的地方。例如:

public class TheClass
{
    MyType x = new MyType();
    public TheClass()
    {
        x = new MyType(/*some arguments*/);
    }
}

这将导致对x进行两次分配,第一次使用默认构造函数,第二次在构造函数内使用新值。这是因为类级变量是在构造函数之前初始化的。