8

Introducing C# 10: Structs parameterless constructor and instance field initiali...

 2 years ago
source link: https://anthonygiretti.com/2022/02/21/introducing-c-10-structs-parameterless-constructor-and-instance-field-initializer/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Introducing C# 10: Structs parameterless constructor and instance field initializer

2022-02-21 by anthonygiretti

Introduction

I’m going to talk in this post about an important feature of C# 10 that has gone rather unnoticed. In addition to record support on structs, C# 10 now allows what was previously only possible on classes: parameterless constructors

Syntax

The operation of constructors without parameters still differs on structs with C# 10 compared to classes. A parameterless constructor cannot be used without field initializers (it’s not really true, I’ll show you further). However, like classes, it is possible, like classes, to use field initializers without a parameterless constructor. The following is legal:

public struct Product { public Product() { }

public string Name { get; set; } = string.Empty; // init can also be used instead of set

public int CategoryId { get; set; } = int.MinValue; // init can also be used instead of set }

The following is not:

public struct Product { public Product() { }

public string Name { get; set; } // Error CS0843 Auto-implemented property 'Product.Name' must be fully assigned before control is returned to the caller.

public int CategoryId { get; set; } // Error CS0843 Auto-implemented property 'Product.CategoryId' must be fully assigned before control is returned to the caller.

}

Note that on structs, parameterless constructors must be declared public, declaring them private or internal will generate an error at compilation.

If you still want to use a parameterless constructor with no field initializer, in fact, it is possible, just initialize the unassigned field in the constructor as follows:

public struct Product { public Product() { CategoryId = int.MinValue; }

public string Name { get; set; } = string.Empty;

public int CategoryId { get; set; } }

This syntax described since the beginning of the section applies to any kind of struct: struct, readonly struct, ref struct, record struct. Keep in mind that the syntax of readonly structs is quite different: readonly modifier must be applied on properties AND you have to remove the get keyword. The following is a legal declaration of a readonly struct:

public readonly struct Product { public Product() { }

public readonly string Name { get; } = string.Empty; public readonly int CategoryId { get; } = int.MinValue; }

The special case of the record struct

It is possible to combine primary constructors, constructors without parameters, constructors with parameters, and fields initializers. There are many possibilities, here are some examples below:

// Example 1 public record struct Product(string Name) { public Product() : this("Disk") { CategoryId = int.MinValue; } // Uses internally the primary constructor public Product(int categoryId) : this("Disk") { CategoryId = categoryId; } // Uses internally the primary constructor

public int CategoryId { get; set; } = int.MinValue; }

// Example 2 public record struct Product(string Name) { public Product(int categoryId) : this() { Name = "Disk"; CategoryId = categoryId; } // Uses internally the implicit parameterless constructor

public int CategoryId { get; set; } = int.MinValue; }

// Example 3 public record struct Product(int CategoryId, string Name) { public Product() : this(int.MinValue, "Disk") { } // Uses internally the primary constructor

public Product(int categoryId) : this(categoryId, "Disk") { } // Uses internally the primary constructor

public Product(string name) : this(int.MinValue) { } // Uses the constructor with the int categoryId parameter }

// Example 4 // Not compiling: Error CS0768 Constructor 'Product4.Product4(string)' cannot call itself through another constructor public record struct Product(int CategoryId, string Name) { public Product() : this(int.MinValue, "Disk") { } // Uses internally the primary constructor

public Product(int categoryId) : this("Disk") { CategoryId = categoryId; } // Uses the constructor with the int categoryId parameter

public Product(string name) : this(int.MinValue) { Name = name; } // Illegal, makes a circular reference with the constructors }

To finish, I would like to notice there is probably a mistake in the Microsoft documentation, the following example (R1). Microsoft says “‘struct’ with field initializers must include an explicitly declared constructor”. After trying the code compile and can be executed without any issue. Once I get a response from Microsoft I’ll update my post. If you want to check the documentation you can find it here: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-10.0/parameterless-struct-constructors#record-struct

Conclusion

As the record struct is a pretty huge feature, I have separated this post from my previous one here: Introducing C# 10: Record struct – Anthony Giretti’s .NET blog. This post introduced also parameterless constructors and fields initializers I haven’t been through all the behavior of this feature, for example I haven’t addressed the default() expression, the new() instruction etc… but you an check them here: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-10.0/parameterless-struct-constructors#default-expression

Like this:

Loading...

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK