为什么要在一行中声明一个变量,并在下一行中分配给它

本文关键字:一行 分配 声明 为什么 一个 变量 | 更新日期: 2023-09-27 18:33:26

我经常在 C# 代码中看到以下约定:

some_type val;
val = something;

喜欢

DataTable dt;
dt = some_function_returning_datatable();

DataTable dt = new DataTable();
dt = some_function_returning_datatable();

而不是

some_type val = something;
DataTable dt = some_function_returning_datatable();

我最初认为这是您必须在范围顶部声明所有局部变量的日子遗留下来的习惯。但是我已经学会了不要这么快就忽视资深开发人员的习惯。

(在我的第 3 个代码部分中,当我们先用 new 然后从函数分配dt时,它不会浪费内存(

那么,有没有充分的理由在一行中声明,然后分配?

为什么要在一行中声明一个变量,并在下一行中分配给它

在我的第 3 个代码部分中,当我们首先使用 new 然后从函数分配 dt 时,它不会浪费内存

是的,确实会。只是相对较小的 - 创建一个无用的DataTable对象 - 但仍然浪费不清楚。

那么,有没有充分的理由在一行中声明,然后分配?

仅当您没有立即获得该值时。例如:

string x;
if (someCondition) {
    // Do some work
    x = someResult;
} else {
    // Do some other work
    x = someOtherResult;
}

通常,可以使用条件运算符或将该代码提取到方法中来改进这一点。不过,有时情况并非如此。

对于以下简单情况:

Foo x = SomeInitializationWithNoUsefulSideEffects();
x = SomeUsefulValue();

Foo x;
x = SomeUsefulValue();

绝对应该重构到

Foo x = SomeUsefulValue();

声明点确实会产生影响的另一个有趣情况是捕获的变量,尽管通常不是它想要的方式:

int x;
for (int i = 0; i < 10; i++) {
    x = SomeFunction();
    actions.Add(() => Console.WriteLine(x));
}

for (int i = 0; i < 10; i++) {
    int x = SomeFunction();
    actions.Add(() => Console.WriteLine(x));
}

在第一个代码段中,每个委托将捕获相同的变量,因此它们都将有效地看到从SomeFunction返回的最后一个值。在第二个代码段中,每个委托将捕获x单独"实例"。

但是我已经学会了不要这么快就忽视资深开发人员的习惯。

很快解雇他们,不用担心或任何犹豫。用 C# 编写是完全没有意义的:

some_type val;
val = something;

而不是:

some_type val = something;

或:

DataTable dt = new DataTable();
dt = some_function_returning_datatable();

而不是:

DataTable dt = some_function_returning_datatable();

无论如何,如果不在代码中消除它们,C# 编译器将在发出生成的 IL 时消除它们。

这是每个人自己的愿望。没有性能问题。由于 CLR 将做出自己的声明,无论您声明如何,无论是在一行还是两行中。

我总是跟随

int i=5;

在可能的情况下。

但要确定,因为当您在单行中声明 int i=5 时,CLR 必须创建一个新的整数实例。

SomeType someVar;
someVar = new(SomeType);

SomeType someVar = new(SomeType);

是等价的。可能是开发人员的习惯,可能是拆分是必要的,但已被重构,但不是完全。

SomeType someVar = new(SomeType);
someVar = GetSomeTypeFromSomewhereElse();

充其量是低效的编码,因为第一个实例显然什么也没做就超出了范围。取决于构造函数中的任何副作用的课程。如果有一些,那么我们将在您的同行评审期间进行漫长而痛苦的聊天。:D

在那之后,正如其他人所说,这是因为必须声明someVar以便可以通过一些进一步的逻辑进行分配。

在读取代码时,知道哪些变量在其范围内会改变,哪些变量不会改变非常有用。 粗略指示这一点的一个有用约定是,如果变量的值在整个范围内保持不变,则在与其声明相同的行上初始化变量,并在与其声明分开的行上初始化它,如果两者兼而有之:

  1. 其值将在其范围内重新分配,并且
  2. 这一事实不会立即显现出来

对于某件事是否"立即显而易见",有一些判断的余地;一些符合条件的情况是:

  1. 变量初始化为明显是常量值的东西(特别是如果它是类型的默认值(
  2. 在其定义的几行内重新分配值
  3. 变量的名称和初始化表达式建议循环初始化(例如"var currentFoo = firstFoo;"(

变量的作用域越长,如果值发生变化,我就越有可能使用单独的初始化和声明。