简体   繁体   English

对象初始值设定项和构造函数之间有什么区别?

[英]What's the difference between an object initializer and a constructor?

What are the differences between the two and when would you use an "object initializer" over a "constructor" and vice-versa?两者之间有什么区别,什么时候使用“对象初始值设定项”而不是“构造函数”,反之亦然? I'm working with C#, if that matters.如果重要的话,我正在使用 C#。 Also, is the object initializer method specific to C# or .NET?此外,对象初始化方法是否特定于 C# 或 .NET?

Object Initializers were something added to C# 3, in order to simplify construction of objects when you're using an object. 对象初始化器是添加到C#3的东西,以便在使用对象时简化对象的构造。

Constructors run, given 0 or more parameters, and are used to create and initialize an object before the calling method gets the handle to the created object. 给定0或更多参数的构造函数运行,并在调用方法获取创建对象的句柄之前用于创建和初始化对象。 For example: 例如:

MyObject myObjectInstance = new MyObject(param1, param2);

In this case, the constructor of MyObject will be run with the values param1 and param2 . 在这种情况下, MyObject的构造函数将使用值param1param2 These are both used to create the new MyObject in memory. 这些都用于在内存中创建新的MyObject The created object (which is setup using those parameters) gets returned, and set to myObjectInstance . 返回创建的对象(使用这些参数设置),并设置为myObjectInstance

In general, it's considered good practice to have a constructor require the parameters needed in order to completely setup an object, so that it's impossible to create an object in an invalid state. 通常,将构造函数需要所需的参数以完全设置对象被认为是一种好的做法,因此无法在无效状态下创建对象。

However, there are often "extra" properties that could be set, but are not required. 但是,通常可以设置“额外”属性,但不是必需的。 This could be handled through overloaded constructors, but leads to having lots of constructors that aren't necessarily useful in the majority of circumstances. 这可以通过重载的构造函数来处理,但是导致有许多构造函数在大多数情况下不一定有用。

This leads to object initializers - An Object Initializer lets you set properties or fields on your object after it's been constructed, but before you can use it by anything else. 这会导致对象初始值设定项 - 对象初始值设定项允许您在对象构造之后设置属性或字段,但您可以通过其他任何方式使用它之前 For example: 例如:

MyObject myObjectInstance = new MyObject(param1, param2)
{
    MyProperty = someUsefulValue
};

This will behave about the same as if you do this: 这与您执行此操作的行为大致相同:

MyObject myObjectInstance = new MyObject(param1, param2);
myObjectInstance.MyProperty = someUsefulValue;

However, in multi-threaded environments the atomicity of the object initializer may be beneficial, since it prevents the object from being in a not-fully initialized state (see this answer for more details) - it's either null or initialized like you intended. 但是,在多线程环境中,对象初始化程序的原子性可能是有益的,因为它可以防止对象处于未完全初始化的状态(有关更多详细信息,请参阅此答案 ) - 它可以为null或初始化,如您所愿。

Also, object initializers are simpler to read (especially when you set multiple values), so they give you the same benefit as many overloads on the constructor, without the need to have many overloads complicating the API for that class. 此外,对象初始化器更易于阅读(特别是当您设置多个值时),因此它们可以为构造函数提供与许多重载相同的好处,而不需要使许多重载使该类的API复杂化。

A constructor is a defined method on a type which takes a specified number of parameters and is used to create and initialize an object. 构造函数是类型上的已定义方法,它采用指定数量的参数并用于创建和初始化对象。

An object initializer is code that runs on an object after a constructor and can be used to succinctly set any number of fields on the object to specified values. 对象初始值设定项是在构造函数之后在对象上运行的代码,可用于将对象上的任意数量的字段简洁地设置为指定值。 The setting of these fields occurs after the constructor is called. 在调用构造函数之后会发生这些字段的设置。

You would use a constructor without the help of an object initializer if the constructor sufficiently set the initial state of the object. 如果构造函数充分设置了对象的初始状态,则可以在没有对象初始值设定项的帮助下使用构造函数。 An object initializer however must be used in conjunction with a constructor. 但是,对象初始值设定项必须与构造函数一起使用。 The syntax requires the explicit or implicit use (VB.Net and C#) of a constructor to create the initial object. 语法要求构造函数的显式或隐式使用(VB.Net和C#)来创建初始对象。 You would use an object initializer when the constructor does not sufficiently initialize the object to your use and a few simple field and/or property sets would. 当构造函数没有充分初始化对象并使用一些简单的字段和/或属性集时,您将使用对象初始值设定项。

When you do 当你这样做

Person p = new Person { Name = "a", Age = 23 };

this is what an object initializer essentially does: 这是对象初始化器基本上做的事情:

Person tmp = new Person(); //creates temp object calling default constructor
tmp.Name = "a";
tmp.Age = 23;
p = tmp;

Now this facilitates behaviour like this . 现在,这有利于类似行为这样 Knowing how object initializers work is important. 了解对象初始化程序的工作方式非常重要。

If you have properties that MUST be set on your object for it to work properly, one way is to expose just a single constructor which requires those mandatory properties as parameters. 如果你的对象必须设置属性才能正常工作,一种方法是只公开一个构造函数,它需要那些必需的属性作为参数。

In that case, you cannot create your object without specifying those mandatory properties. 在这种情况下,如果不指定这些必需属性,则无法创建对象。 Something like that cannot be enforced by object initializers. 对象初始化器无法强制执行类似的操作。

Object initializers are really just a "syntax convenience" to shorten initial assignments. 对象初始化器实际上只是缩短初始分配的“语法便利”。 Nice, but not really very functionally relevant. 不错,但功能上并非真正相关。

Marc

A constructor is a method (possibly) accepting parameters and returning a new instance of a class. 构造函数是一种方法(可能)接受参数并返回类的新实例。 It may contain initialization logic. 它可能包含初始化逻辑。 Below you can see an example of a constructor. 您可以在下面看到构造函数的示例。


public class Foo
{
    private SomeClass s;
    public Foo(string s)
    {
       s = new SomeClass(s);
    }
}

Now consider the following example: 现在考虑以下示例:


public class Foo
{
    public SomeClass s { get; set; }
    public Foo() {}
}

You could achieve the same result as in the first example using an object initializer, assuming that you can access SomeClass, with the following code: 您可以使用对象初始值设定项获得与第一个示例中相同的结果,假设您可以使用以下代码访问SomeClass:


new Foo() { s = new SomeClass(someString) }

As you can see, an object initializer allows you to specify values for public fields and public (settable) properties at the same time construction is performed, and that's especially useful when the constructor doesn't supply any overload initializing certain fields. 如您所见,对象初始值设定项允许您在执行构造的同时指定公共字段和公共(可设置)属性的值,并且在构造函数不提供任何重载初始化某些字段时尤其有用。 Please mind, however that object initializers are just syntactic sugar and that after compilation won't really differ from a sequence of assignments. 请注意,然而,对象初始化器只是语法糖,并且在编译之后将不会与分配序列真正不同。

Object initializers can be useful to initialize some small collection which can be used for testing purposes in the initial program creation stage.对象初始值设定项可用于初始化一些小集合,这些集合可用于初始程序创建阶段的测试目的。 The code example is below:代码示例如下:

    class Program
    {
        static void Main(string[] args)
        {
            List<OrderLine> ordersLines = new List<OrderLine>()
            {
                new OrderLine {Platform = "AmazonUK", OrderId = "200-2255555-3000012", ItemTitle = "Test product 1"},
                new OrderLine {Platform = "AmazonUK", OrderId = "200-2255555-3000013", ItemTitle = "Test product 2"},
                new OrderLine {Platform  = "AmazonUK", OrderId = "200-2255555-3000013", ItemTitle = "Test product 3"}
            };
        }
    }
    class OrderLine
    {
        public string Platform { get; set; }
        public string OrderId { get; set; }
        public string ItemTitle { get; set; }
    }

Here is the catch.这是陷阱。 In the above code example isn't included any constructor and it works correctly, but if some constructor with parameters will be included in the OrderLine class as example:在上面的代码示例中没有包含任何构造函数并且它可以正常工作,但是如果一些带参数的构造函数将包含在 OrderLine 类中作为示例:

public OrderLine(string platform, string orderId, string itemTitle)
{
   Platform = platform;
   OrderId = orderId;
   ItemTitle = itemTitle;
}

The compiler will show error - There is no argument given that corresponds to the required formal parameter….编译器将显示错误 - 没有给定的参数对应于所需的形式参数……。 It can be fixed by including in the OrderLine class explicit default constructor without parameters:它可以通过在 OrderLine 类中包含不带参数的显式默认构造函数来修复:

public OrderLine() {}

Object initializers are especially useful in LINQ query expressions.对象初始值设定项在 LINQ 查询表达式中特别有用。 Query expressions make frequent use of anonymous types, which can only be initialized by using an object initializer, as shown in the code example below:`查询表达式经常使用匿名类型,只能使用对象初始化器来初始化,如下面的代码示例所示:`

var orderLineReceiver = new { ReceiverName = "Name Surname", ReceiverAddress = "Some address" };

More about it - Object and collection initializers关于它的更多信息 - 对象和集合初始值设定项

Now, years later, I am reconsidering the use of Constructors over Object Initializers.多年后的现在,我正在重新考虑使用构造函数而不是对象初始值设定项。 I have always liked Object initializers, as they are quick and easy.我一直很喜欢对象初始值设定项,因为它们又快又简单。 Pick which fields you want to set, and set them and you are done.选择要设置的字段,然后设置它们即可。

But then along came along the nullable context wherein you must specify which properties are nullable, and which are not.但随之而来的是nullable context ,您必须在其中指定哪些属性可以为空,哪些不能。 If you ignore using a constructor, and instead use an object initializer, the compiler is not going to be assured that your object is in fact whole (no null properties which should in fact be non-null) But a properly written and used constructor resolves all of that.如果您忽略使用构造函数,而是使用对象初始值设定项,编译器将无法确保您的对象实际上是完整的(没有空属性,实际上应该是非空的)但是正确编写和使用的构造函数可以解决所有的。

But an even better solution is to use the "required" keyword on the fields that are expected to be populated on creation, whether through a constructor, or an object Initializer.但更好的解决方案是在创建时预期填充的字段上使用“required”关键字,无论是通过构造函数还是对象初始化程序。 It's a new keyword of C# 11, which comes with .net 7 .net 7自带的C#11的新关键字

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 默认构造函数和默认构造函数之间的区别是什么 - what's the difference between the default and default constructor 内部类中的公共构造函数和内部构造函数之间有什么区别? - What's the difference between a public constructor in an internal class and an internal constructor? 对象和变量之间有什么区别? - What's the difference between object and variable? new object [] {}和new [] {}有什么区别? - What's the difference between new object[] {} and new [] {}? CancellationTokenSource构造函数延迟参数和CancelAfter方法有什么区别 - What's the difference between CancellationTokenSource constructor delay parameter and CancelAfter Method 简单构造函数和带有基数的构造函数有什么区别? - What is the difference between simple constructor and constructor with base? 在F#中,具有强制构造函数参数的对象初始化程序语法是什么? - In F#, what is the object initializer syntax with a mandatory constructor parameter? IEquatable 和只是覆盖 Object.Equals() 有什么区别? - What's the difference between IEquatable and just overriding Object.Equals()? 在循环内部和外部创建对象之间的内存区别是什么 - What's the difference in memory between creating an object inside and outside of a loop 构造函数或字段定义中的实例化有什么区别? - What is the difference between instantiation in constructor or in field definition?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM