2012-03-29 58 views
2

在C#中使用对象初始值设定项时,是否可以执行规则或引发错误?我想抛出一个编译器错误或警告,如果一个对象被初始化但缺少某个属性。对象初始值设定程序强制编译错误

public class Party 
{ 
    public string Name { get; set; } 
    public string Date { get; set; } 
    public Location Location { get; set; } 
} 

public class SignUpForParty 
{ 
    public void DoSomething() 
    { 
     Party party = new Party() 
     { 
      Name = "New Years Party!", 
      Date = "Dec 31, 1999" 
      // Show WARNING/ERROR here because no Location given 
     }; 
    } 
} 

本质上,我正在寻找一种方法来确保所有类型为Party的对象都使用每个实例的有效数据创建。

很明显,我可以用重载的构造函数做到这一点,但在某些情况下,我有很多属性和编写构造函数来匹配是混乱的。我想遵循更清晰的C#风格。

Obj p = new Obj(1, 2, 3,...n); // too many properties to be pretty 
+1

你可以把每个构造函数参数放在它自己的行上,而且看起来很相似。你提到构造函数重载,但你也说你想要*所有*属性设置,这表明一个超级构造函数。 – dlev 2012-03-29 01:16:17

+0

感谢您的答案。我混淆了对象发起者与构造函数。我想要两全其美 - 建立一个强制执行的对象,但要有简单的对象启动器风格。我不想要一堆超级构造函数。 What @ reed-copsey在我的场景中也是如此,因为我们需要的是构造函数,可选的东西应该留给启动器。 – daviddeath 2012-03-29 02:53:12

回答

4

显然我可以用重载的构造函数做到这一点,但在某些情况下,我有很多属性和编写构造函数来匹配是凌乱的。我想遵循更清晰的C#风格。

对象初始值设定项实际上不应被视为写入构造函数的替代方法。

如果你有这样的要求,你应该总是在你的类型中包含构造函数。创建一组默认的构造函数(或者在一个构造函数上使用可选参数)是一个好主意,它至少能够保证对象始终以有效的,有意义的状态创建。

对象初始值设定对可选属性有帮助,但不应该依赖于类型本身的要求。

3

您无法强制每个属性都使用对象初始值设定项进行初始化。

即使可以,对象的使用者也可以提供默认值(0,null,...)。根据您的需要,考虑在关键时间验证对象状态(例如,在可以将其保存到数据库之前)。

如果你走这条路线,看看IDataErrorInfo接口。

2

如果您的类型仅在设置了2个属性时无效,那么您需要修复您的设计,而不是发出错误。

您提供了一个默认的构造函数,它告诉我,在初始化后我不必设置任何东西来使用该对象。你为每个属性提供getter和setter,再次隐式告诉你的类的用户可以设置,但不能设置另一个。

如果情况并非如此,那么我建议你提供一个构造函数,它迫使我提供所有三个值。是的,我仍然可以使用(null, null, null),但是您可以检查并输出错误。

此外,如果PropertyA取决于PropertyB然后要么

A)只有它们中的一个应该有一个设置器,或

B)应该有逻辑在每个设定器正确初始化其它值改变后。

这是一个设计问题,而不是语言问题。您不能强制初始化器语法的工作方式与其指定方式不同。

Obj p = new Obj(1,2,3,... n); //太多漂亮的属性

代码不应该是'漂亮',它应该工作。即便如此,一个接受几个参数的构造函数是'丑陋'?咦?不要购买时髦的废话,编写可行的代码并运行良好。

+0

同意所有观点,谢谢。 “...你提供了一个构造函数,它迫使我提供所有三个值” - 我可能会更好地理解我的问题:“我可以提供带构造函数的构造函数的行为吗?”我了解到,这不是。 – daviddeath 2012-03-29 03:11:37

0

我可以看到这个实现的唯一方法是当对象初始化器完成时引发了一些事件(或等价物)。目前有一个Connect request为这个效果。

不幸的是,我并没有获得晋级的.NET 4.5:

谢谢您的建议。

这是一个很棒的主意,它具有很好的属性,它不会添加到语言表面 - 它只是使对象初始化变得更加智能。原则上这可能会使其成为一个突破性的改变,但这是我们可以研究的。

不幸的是,我们不能再添加到我们目前正在构建的版本中,所以我将解决此问题。但是,我正在捕获关于我们未来讨论的功能列表的建议。

再次感谢!

的Mads托格森,C#语言PM

也许这将使它的方式进入.NET 5+。

+0

这是一个非常有趣的想法。在很多方面,这几乎是我正在寻找的。 – daviddeath 2012-03-29 02:49:33

+0

@daviddeath - 不幸的是,目前没有提供这种功能的解决方法,所以我只能建议对连接请求进行投票,希望它能够进入下一个版本。我认为今天唯一可行的(考虑到我们目前的限制)将是使用所提出的想法。也许不久之后。 – 2012-03-29 02:54:07

0

怎么样Code Contracts?这将断言你不仅分配了一个值,还可以指定有效的范围。

或者仅在运行时使用调试版本进行检查,您可以使用Debug.Assert(...)调用实现与上述相同的调用。