嗨,我在C#中使用初始化块。
new Something { foo = 1, bar = 2 };
但是有人说这是不好的做法。
我不认为这是错误的,不是吗?
嗨,我在C#中使用初始化块。
new Something { foo = 1, bar = 2 };
但是有人说这是不好的做法。
我不认为这是错误的,不是吗?
你需要思考一下你的类型是否应该是可变的。就我个人而言,我喜欢不可变类型-它们使得理解正在发生的事情更容易,验证也更容易(一旦调用了构造函数并验证了状态,你就知道它不会变成无效状态),对于并发编程也非常有用。
另一方面,对象初始化程序在允许使用可变类型的情况下确实很有用。例如,ProcessStartInfo
实际上被用作 Process
的建造者类型。这样写是很有用的:
var info = new ProcessStartInfo {
FileName = "notepad.exe",
Arguments = "foo.txt",
ErrorDialog = true
};
Process process = Process.Start(info);
事实上,你甚至可以内联执行所有操作,而不需要使用额外的变量。我的 Protocol Buffers 代码库使用了相同的模式:
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
);
这种方式在清晰度方面有许多与对象初始化器相同的好处,但没有可变性的惩罚。上面的构造函数调用可能会省略一些可选参数,如附件和BCC列表。我认为这将证明是C# 4中最大的收益之一,对于那些喜欢不可变性但也喜欢对象初始化器清晰度的人来说。
Fool x = new Fool("John" /* First */, "Doe" /* Last */, 79 /* Age */);
,它们可以帮助区分模糊的方法调用,当其中一个参数为null时,但是否存在使用命名参数会适得其反的情况呢? - Hamish Grubijanpublic 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" };
你不知道构造函数在做什么。在某些情况下,构造对象然后设置公共属性可能比通过构造函数本身传递值显著地增加了成本。(您可能知道这不是事实,但作为类的使用者,您不应该假定关心实现细节,因为它们可能会发生变化)。
如果其中一个或多个属性的名称更改或变为只读状态(第一个属性ID可能本来就应该是只读的,但由于ORM之类的架构限制而不是),您的代码不会出错。
然而,在一种情况下,您必须使用初始化器而不是重载的构造函数,那就是在Linq to SQL / EF查询中链接选择时:
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 { ... };
ClientBase<T>
)是构造成本高的对象之一。我编写的许多类将在默认构造函数中执行默认初始化任务。虽然我不反对您关于可读性的观点,但也很重要意识到初始化器只是属性设置器的语法糖(即var x = new MyClass(); x.ID = 1; x.Name = "Fred";
),这与向构造函数提供这些值的语义根本不同。 - Aaronaught但是有人说这是不好的做法。
谁说的?至少,这是一个有争议的说法。
目前似乎非常流行,许多知名的C#博客都广泛使用它。
与使用构造函数相比,优点在于它更易读,因为代码清楚地显示了哪些属性被分配了什么值。比较一下:
var x = new Something { Foo = 1, Bar = 2 };
使用
var x = new Something(1, 2);
var x = new Something();
x.Foo = 1;
x.Bar = 2;
就我个人而言,我更喜欢不可变对象(即一旦创建,就不能更改的对象)。不幸的是,初始化程序块不能与这种对象(目前)结合使用,因为要使此模式起作用,对象必须具有属性设置器,而不可变对象没有。
但只要所使用的对象不是不可变的,我认为没有什么强烈的理由反对使用初始化程序符号。
初始化块是以下几个方面的良好实践:
You get to create an object and override its properties before getting its reference
this.ObjA = new ObjA
{
Age = 20,
Name = "123",
};
// this.ObjA will not be set until properties have all been defined
// - safer when multithreading
The parameter-less constructor can still do things behind the scene (e.g. initialize state members).
You can use in conjunction with constructors with parameters
this.ObjA = new ObjA(20)
{
Name = "123",
};
Using parameter-less constructors is better for (de)serializing scenarios
You can create various objects, change their state via GUI, serialize them, deserialize them elsewhere.
This practice forces authors to write more robust code - where the order in which things are done is less lightly to cause the application to crash every time the class's metadata is changed.
this.ObjA = new ObjA(Age: 20, Name: "123");
? - NetMage初始化块没有问题,但是如果您的类型例如有许多属性,而只有其中几个需要在每个实例上设置,则应该在构造函数中将它们设为必需。
您类的用户将知道他们无法创建对象而不指定这些值。
对于对象工作所必需的属性,应在构造函数中进行初始化,因此您应该在构造函数中提供适当的参数。
初始化块非常适用于C# 3.0的几个新功能,但请记住,它们并不是用来替换构造函数中的参数的。
我认为这很不错。
因为它可以大大减少你的打字量。