重新初始化变量或声明新的?

时间:2009-07-27 16:57:08

标签: c#

在C#中,重新初始化先前声明的变量而不是声明和初始化新变量是否有利有弊? (忽略关于简洁性和人类可读性的想法。)

例如,比较这两个样本:

DataColumn col = new DataColumn();
col.ColumnName = "Subsite";
dataTable.Columns.Add(col);

col = new DataColumn(); // Re-use the "col" declaration.
col.ColumnName = "Library";
dataTable.Columns.Add(col);

VS

DataColumn col1 = new DataColumn();
col1.ColumnName = "Subsite";
gridDataTable.Columns.Add(col1);

DataColumn col2 = new DataColumn(); // Declare a new variable instead.
col2.ColumnName = "Library";
gridDataTable.Columns.Add(col2);

涉及循环的类似示例:

string str;
for (int i = 0; i < 100; i++)
{
    str = "This is string #" + i.ToString(); // Re-initialize the "str" variable.
    Console.WriteLine(str);
}

VS

for (int i = 0; i < 100; i++)
{
    string str = "This is string #" + i.ToString(); // Declare a new "str" each iteration.
    Console.WriteLine(str);
}

编辑:到目前为止,谢谢大家的答案。读完之后,我想我会稍微扩展一下我的问题:

如果我错了,请纠正我。

当我声明并初始化类似System.String的引用类型时,我有一个指向该对象的指针,该对象存在于堆栈中,而对象的内容存在于堆上(只能通过指针访问)。 / p>

在第一个循环示例中,似乎我们只创建了一个指针“str”,我们创建了100个String类的实例,每个实例都存在于堆上。在我看来,当我们遍历循环时,我们只是将“str”指针改为每次都指向String类的新实例。那些不再指向它们的“旧”字符串将被垃圾收集 - 尽管我不确定何时会发生这种情况。

在第二个循环示例中,除了创建100个String类实例之外,我们似乎创建了100个指针。

我不确定堆栈中不再需要的项目会发生什么。我不认为垃圾收集器也摆脱了这些物品;也许一旦你退出他们的范围,他们会立即从堆栈中删除?即使这是真的,我认为只创建一个指针并更新它指向的内容比创建100个不同的指针更有效,每个指针指向一个唯一的实例。

我理解“过早优化是邪恶的”论点,但我只是想要更深入地了解事物,而不是将我的程序优化为死亡。

5 个答案:

答案 0 :(得分:6)

你的第二个例子有一个更清晰的答案,第二个例子是更好的答案。原因是变量str仅在for块中使用。在for块之外声明变量意味着另一段代码可能会错误地绑定到此变量,从而导致应用程序中出现错误。您应该在最具体的范围内声明所有变量,以防止意外使用。

对于第一个样本,我认为这更符合偏好。对我来说,我选择创建一个新变量,因为我相信每个变量都应该有一个目的。如果我重用变量,通常表明我需要重构我的方法。

答案 1 :(得分:1)

这听起来像是一个旨在为过早优化提供信息的问题。我怀疑这两种情况在99.9%的软件中都有所不同。正在以任何一种方式创建和使用内存。唯一的区别是变量引用。

要了解是否存在利弊,您需要一种真正关心装配体尺寸或性能的情况。如果你不能满足尺寸要求,那么测量两个选择之间的装配尺寸差异(尽管你更有可能在其他领域获得收益)。如果您无法满足性能要求,请使用分析器查看代码的哪一部分工作太慢。

答案 2 :(得分:1)

这主要是一个可读性问题,无论您使用相同的声明名称是否无关紧要,因为您要么创建两个单独的对象。你真的应该考虑到一个焦点来创建对象或变量,它会让你的生活更轻松。

至于你的第二个例子,初始化的唯一真正区别在于,通过将你的字符串放在“for”循环的范围之外,你会让它暴露在更多的外部影响之下,这有时会很有用。在循环内部或外部声明它没有内存或速度优势。请记住,无论何时对字符串变量进行更改,您实际上都在创建一个新字符串。所以,例如:

string test = "new string";
test = "and now I am reusing the string";

与创建两个单独的字符串相同,例如:

string test1 = "new string";
string test2 = "and now I am reusing the string";

要解决此问题,您可以使用StringBuilder类,它允许您在不创建新字符串的情况下修改字符串,并且应该在字符串被大量修改的情况下使用,尤其是在循环内部

答案 3 :(得分:0)

使用“使用”这个词在括号结束后破坏对象本身怎么样? 我不确定,但这就是我的想法。我也想知道你的意见。

对于第二个例子,我总是使用第二个例子,我也不确定,但是例如在ACM-ICPC比赛中的一些问题我曾经因为忘记重新初始化而丢失了错误,所以我用这种方式。

答案 4 :(得分:0)

在大多数情况下,不,应该没有区别。主要区别在于局部变量(在类的情况下,它们的“指针”)存储在堆栈中,在第一种情况下,如果你的函数由于某种原因递归,有两个本地变量而不是一个会导致你在深度递归函数中更快地耗尽堆栈空间。在任何一种情况下都接近这个限制将表明您应该使用非递归方法。

另外,只需提及它,您可以完全跳过变量并写下:

dataTable.Columns.Add(new DataColumn() { ColumnName = "Subsite" });
dataTable.Columns.Add(new DataColumn() { ColumnName = "Library" });

我认为性能方面就像拥有2个局部变量,但我可能错了。我无法准确记住IL代码中产生的内容。