在设计课程时,是否有关于初始化课程字段的指导原则?有两种不同的初始化方法。我可以使用内联字段初始化程序,或者我可以在构造函数中初始化它们。它变得更加有趣,当引入静态字段时,字段可以在定义时,静态构造函数或实例构造函数中初始化,并检查字段是否已经设置。当工厂推出时,这会变得更加混乱。
示例1 - 内联启动
public class ExampleOne
{
private readonly IDictionary _collection = new Dictionary();
...
}
示例2 - 构造函数初始化
public class ExampleTwo
{
private readonly IDictionary _collection;
public ExampleTwo()
{
_collection = new Dictionary();
}
...
}
示例3 - 静态内联初始化
public class ExampleThree
{
private static readonly IDictionary __collection = new Dictionary();
...
}
示例4 - 静态构造函数初始化
public class ExampleFour
{
private static IDictionary __collection;
static ExampleFour()
{
_collection = new Dictionary();
}
...
}
示例5 - 静态/实例构造函数混合初始化
public class ExampleFive
{
private static readonly IDictionary __collection;
private static IDictionary __anotherCollection;
static ExampleFive()
{
_collection = new Dictionary();
}
public ExampleFive()
{
if( __anotherCollection == null )
{
__anotherCollection = new Dictionary();
}
}
...
}
示例6 - 工厂方法
public class ExampleSix
{
private static readonly IDictionary __collection;
private static IDictionary __anotherCollection;
static ExampleSix()
{
_collection = new Dictionary();
}
public static ExampleSix Create()
{
if( __anotherCollection == null )
{
__anotherCollection = new Dictionary();
}
var example = new ExampleSix();
return example;
}
...
}
目前我所拥有的课程往往会混合所有这些课程。虽然我试图避免在实例构造函数中设置静态字段。
示例7 - 混合
public class ExampleSeven
{
private static readonly IDictionary __collection = new Dictionary();
private static readonly IDictionary __anotherCollection;
private static readonly IDictionary __thirdCollection;
private static IDictionary __fourthCollection;
static ExampleSeven()
{
__anotherCollection = new Dictionary();
}
public ExampleSeven()
{
if( __thirdCollection == null )
{
__thirdCollection = new Dictionary();
}
}
public static ExampleSeven Create()
{
if( __fourthCollection == null )
{
__fourthCollection = new Dictionary();
}
var example = new ExampleSeven();
return example;
}
...
}
我更关注的是,在示例中可以看到,字段是类对象而不是简单的基元。我知道在声明字段时初始化字段会将类标记为beforeinit
,并且我无法将this
传递给声明时初始化的字段。我关注的主要是与上述七个例子类似的情况。我是否通过这种方式将它们混合在一起来解决任何不可预见的问题?
答案 0 :(得分:2)
通常,无论是在构造函数中初始化字段还是使用字段初始值设定项,都无关紧要。但是,关于操作的时间和顺序,您应该注意一些细微之处:
实例字段初始值设定项和实例构造函数按以下顺序运行,这可能会令人惊讶:
请参阅Eric Lippert撰写的文章,讨论此行为的原因:http://blogs.msdn.com/b/ericlippert/archive/2008/02/18/why-do-initializers-run-in-the-opposite-order-as-constructors-part-two.aspx
要回答您的问题,关于您应该在何处初始化字段没有明确的规则。如果初始化很短,有时初始化字段“inline”更自然,但如果它很长,它应该在构造函数中。有时字段要在构造函数中初始化,因为字段初始值设定项不能包含对this
的引用。我的代码中经常混合使用这两种样式,到目前为止我还没有遇到问题。请记住上面提到的执行顺序......
答案 1 :(得分:0)
这个问题不仅有一个答案。相反,它取决于你想在场上存储什么样的东西以及你想用它做什么。
首先,问问自己:ExampleX绝对需要此字段中的对象吗?是否所有ExampleX的用例都涉及该字段?如果没有,则不应在构造函数中创建它。如果它只是在一个方法中使用,则应该在该方法中创建(或传入)。如果它在两个或多个方法中使用,那么这些可能应该在它们自己的类中,即将类拆分为两个,一个依赖于该字段中的对象而另一个则不依赖。
其次,每次创建ExampleX时,您真的需要一个新词典吗?让我们改变一下这个例子 - 而不是字典,它是某种服务提供对象,设置起来很昂贵,但很容易重复使用。在这种情况下,你应该明确地传递它而不是创建它 - 如果你创建一个新的,你浪费资源,以及使你的程序更复杂,更不易读,因为你引入了隐藏的依赖。通过传入对象,您可以在构造函数签名(或方法签名,如果您将其传递给方法)中公布依赖项。更不用说使其无法测试或难以测试(在单元测试的意义上)。见http://misko.hevery.com/2008/09/30/to-new-or-not-to-new/
所以,总结一下 - 你总是需要它吗?这告诉您是否在构造函数或其他地方创建/传入对象。它必须是新的吗?这将告诉您是创建它还是传入它。
传入内容也会让您的代码变得更加灵活。见http://www.kevinwilliampang.com/2009/11/07/dependency-injection-for-dummies/