C# 使用初始化程序块不好吗
嗨,我在C中使用初始值设定项块# 但人们说这是一种不好的做法 我不认为这是错的,是吗 但人们说这是一种坏习惯 这是谁说的?至少,这是一个有争议的声明 目前它似乎风靡一时,许多著名的C#blog都广泛使用它 与使用构造函数相比,它的优点是可读性更强,因为代码清楚地显示了哪些属性被分配了哪些值。比较:C# 使用初始化程序块不好吗,c#,coding-style,initialization,C#,Coding Style,Initialization,嗨,我在C中使用初始值设定项块# 但人们说这是一种不好的做法 我不认为这是错的,是吗 但人们说这是一种坏习惯 这是谁说的?至少,这是一个有争议的声明 目前它似乎风靡一时,许多著名的C#blog都广泛使用它 与使用构造函数相比,它的优点是可读性更强,因为代码清楚地显示了哪些属性被分配了哪些值。比较: var x = new Something { Foo = 1, Bar = 2 }; 与 此外,如果没有合适的构造函数,则代码比手动指定属性更简洁: var x = new Something()
var x = new Something { Foo = 1, Bar = 2 };
与
此外,如果没有合适的构造函数,则代码比手动指定属性更简洁:
var x = new Something();
x.Foo = 1;
x.Bar = 2;
就个人而言,我更喜欢不可变的对象(即一旦创建就无法更改的对象)。不幸的是,初始化程序块不能与这些对象结合使用(目前),因为要使这种模式工作,对象必须有属性设置器,而不可变对象没有属性设置器
但只要所使用的对象不是不可变的,我就看不出有什么令人信服的理由反对使用初始值设定符号。我认为这是好的
因为它大大减少了输入初始值设定项块没有问题,但是如果您的类型(例如)有许多属性,并且每个实例上只需要设置几个属性,那么您应该在构造函数中要求它们
类的用户将知道,如果不指定这些值,他们将无法创建对象 初始化程序块是一种很好的做法,原因如下:
this.ObjA = new ObjA
{
Age = 20,
Name = "123",
};
// this.ObjA will not be set until properties have all been defined
// - safer when multithreading
this.ObjA = new ObjA(20)
{
Name = "123",
};
public class Entity
{
public Entity()
{
}
public Entity(int id, string name)
{
this.ID = id;
this.Name = name;
}
public int ID { get; set; }
public string Name { get; set; }
}
如果您有这个非常简单的类,那么通常最好编写:
var entity = new Entity(1, "Fred");
var entity = new Entity { ID = 1, Name = "Fred" };
var info = new ProcessStartInfo {
FileName = "notepad.exe",
Arguments = "foo.txt",
ErrorDialog = true
};
Process process = Process.Start(info);
…而不是写:
var entity = new Entity(1, "Fred");
var entity = new Entity { ID = 1, Name = "Fred" };
var info = new ProcessStartInfo {
FileName = "notepad.exe",
Arguments = "foo.txt",
ErrorDialog = true
};
Process process = Process.Start(info);
这至少有两个很好的理由:
ID
可能本来应该是只读的,但可能不是由于ORM之类的体系结构约束)var bars =
from f in ctx.Foo
select new Bar { X = f.X, Y = f.Y };
var bazzes =
from b in bars
select new Baz { ... };
如果使用构造函数重载而不是默认构造函数+初始值设定项,则这实际上可能会因“不支持映射”而失败。然而,这是所使用技术的一个限制(这是一个不受欢迎的限制),而不是编码风格的问题
在其他情况下,您应该更喜欢构造函数重载而不是初始值设定项
如果没有有用的/相关的构造函数重载可以做与初始值设定项相同的事情,那么继续编写初始值设定项,它没有问题。该功能的存在有一个很好的理由-它使代码更易于编写和读取。对于对象工作至关重要的属性应该在构造函数中初始化,因此您应该在contstructor中提供适当的参数
初始化程序块对于C#3.0的一些新功能非常方便,但是您应该记住,它们不是用来替换构造函数中的参数的。您需要问问自己,您的类型是否应该是可变的。就我个人而言,我喜欢不可变类型——它们使我们更容易对正在发生的事情进行推理,更容易进行验证(一旦调用了构造函数并验证了状态,您就知道它不会变得无效),而且它们对于并发性非常好 另一方面,对象初始值设定项在具有可变类型的情况下当然很有用。例如,
ProcessStartInfo
有效地用作Process
的生成器类型。能够写以下内容很有用:
var entity = new Entity(1, "Fred");
var entity = new Entity { ID = 1, Name = "Fred" };
var info = new ProcessStartInfo {
FileName = "notepad.exe",
Arguments = "foo.txt",
ErrorDialog = true
};
Process process = Process.Start(info);
实际上,您甚至可以内联完成所有这些操作,而无需使用额外的变量。我的协议缓冲区端口使用相同类型的模式:
Foo foo = new Foo.Builder {
FirstProperty = "first",
SecondProperty = "second"
}.Build();
现在,构建器模式的一个替代方案是构造函数参数(可能通过工厂方法)。历史上的缺点是,根据设置的属性,您需要不同的重载,如果多个参数具有相同的类型,则很难区分哪个是哪个。C#4使用可选参数和命名参数使这一过程变得非常简单。例如,如果您正在构建一个电子邮件类,您可以:
Email email = new Email(
from: "skeet@pobox.com",
to: "jon@example.com",
subject: "Test email",
body: textVariable
);
在清晰性方面,这与对象初始值设定项有许多相同的优点,但没有可变性惩罚。上面的构造函数调用可能遗漏了一些可选参数,例如附件和密件抄送列表。我认为这将证明是C#4对我们这些喜欢它的人的最大好处之一