为了使类实例正常工作,应该正确初始化一些字段,初始化这些字段的策略是什么,应该通过构造函数给出什么,应该通过属性给出什么?
我的困惑是,如果构造函数需要一个长参数列表,那么很难使用,如果通过属性,我倾向于忘记设置一些属性。
最佳做法是什么?
答案 0 :(得分:2)
这始终是一种平衡行为 - 您不希望构造函数需要许多参数,但您也不希望在对象处于有效状态之前要求用户设置许多属性。不幸的是,这里没有真正的指导,因为你必须根据当前的情况使用最佳判断。
很多时候,您可能需要创建一个具有许多属性和许多可能配置的复合类型(例如System.Web.Page
)。复合类型往往具有简单的构造函数,这些构造函数很少或不需要参数,并且所有值都必须通过属性设置。复合类型是由低级因子(或原始)类型组成的高级类型。
分解类型往往更简单,包含更少的状态,并且可以通过其构造函数完全初始化。因子类型的示例是System.String
和System.Int32
。这些类型非常简单,往往是复合类型的构建块。
如果您的类型是因式类型,那么请尽量让消费者通过构造函数完全初始化类型。如果您的类型是复合类型,那么最好提供参数很少或没有参数的简单构造函数,并要求使用者通过属性设置器配置实例。
答案 1 :(得分:2)
你必须问自己,如果你的班级需要创造很多东西,也许它做得太多了。这表明你应该重新考虑你的设计,或者说构造者正在做多少“工作”。
确实,您无法创建具有无效状态的实例;因此构造函数应该将所需的所有属性置于有效状态。
在某种程度上,这取决于您的型号。例如,我使用的ORM有构造函数接受一个参数;一个ID,可以通过它加载所有其他属性。如果我不得不将它们全部传递(这实际上是ORM的工作;设置此对象)会很烦人。所以在这个意义上,你可以说你有一个“无效”的对象(没有设置属性)。但你错了;你实际拥有的是一个“空白”或“空”对象。这与无效无关。
因此,请仔细考虑对象的“无效”意味着什么。如果其他方法使用此对象,我会认为它无效,并因为未设置某些内容而抛出异常。使用此逻辑来确定构造函数中需要什么,以及稍后可以设置的内容(通过其他一些过程)。
答案 2 :(得分:1)
既然.NET 3.5允许你在创建时设置任何属性,我通常会将任何带参数的构造函数限制为实例绝对必须在创建时具有值的情况。确实没有任何其他理由使用参数IMO添加构造函数重载。
答案 3 :(得分:1)
我认为最好的方法是执行验证,并且通常会尝试保持没有参数的构造函数,因为它通常是不同.NET库的要求。
通过验证,您必须检查对象的有效性,但这是很常见的事情。行间的一些事情:
public interface IValidateable {
IEnumerable<string> Validate();
}
public class Person : IValidateable {
public string Title { get; set; }
public string First { get; set; }
public string Last { get; set; }
public Address HomeAddress { get; set; }
public Person() {
HomeAddress = new Address();
}
public IEnumerable<string> Validate() {
var errors = new List<string>();
if (string.IsNullOrEmpty(First))
errors.Add("First name is required.");
// And so on...
return errors;
}
}
// Usage
var p1 = new Person();
var p2 = new Person {
First = "Dmitriy"
};
if (p1.Validate().Any()) {
// Do something with invalid object
}