Skip to content

Commit

Permalink
Small tweaks to structs concept docs (#2346)
Browse files Browse the repository at this point in the history
  • Loading branch information
BNAndras authored Dec 10, 2024
1 parent f3c98a6 commit 0b8b0a3
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 12 deletions.
38 changes: 27 additions & 11 deletions concepts/structs/about.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
# About

C# `struct`s are closely related `class`s. They have state and behavior. They can have the same kinds of members: constructors, methods, fields, properties, etc.
C# `struct`s are closely related to `class`es.
They have state and behavior.
They can have the same kinds of members: constructors, methods, fields, properties, etc.

Fields and properties can be simple types, `struct`s or reference types. `struct`s observe the same rules about scope, read/write rules and access levels as do `class`s.
Fields and properties can be simple types, `struct`s or reference types.
`struct`s observe the same rules about scope, read/write rules and access levels as do `class`es.

```csharp
enum Unit
Expand Down Expand Up @@ -32,9 +35,11 @@ new Weight(77.5, Unit.Kg).ToString();
// => "77.6Kg"
```

One of the main things to remember is that when one struct is assigned to a variable or passed as a parameter the values are copied across so changes to the original variable will not affect the copied one and vice versa. In summary, `struct`s are **value types**.
One of the main things to remember is that when one struct is assigned to a variable or passed as a parameter the values are copied across so changes to the original variable will not affect the copied one and vice versa.
In summary, `struct`s are **value types**.

This [article][class-or-struct] discusses the differences between `struct`s and `class`s. You will see from the article that `struct`s tend to be lightweight and [immutable][structs-immutable] although this guidance is not enforced (by default) by the compiler or runtime.
This [article][class-or-struct] discusses the differences between `struct`s and `class`es.
You will see from the article that `struct`s tend to be lightweight and [immutable][structs-immutable] although this guidance is not enforced (by default) by the compiler or runtime.

There are a couple of things that you will come up against (and about which the compiler will remind you):

Expand All @@ -46,21 +51,32 @@ As a result of points 1 and 3 above there is no way for the developer of a `stru

## Common structs

You will see from the documentation that there is a close relationship between primitives and structs. See [`Int32/int`][int32], for an example. A more conventional example of a`struct`is the type [`TimeSpan`][time-span].
You will see from the documentation that there is a close relationship between primitives and structs.
See [`Int32/int`][int32], for an example.
A more conventional example of a`struct`is the type [`TimeSpan`][time-span].

Instances of `TimeSpan` behave much like numbers with comparison operators like `>` and `<` and arithmetic operators. You can implement these operators for your own `struct`s when you need them.
Instances of `TimeSpan` behave much like numbers with comparison operators like `>` and `<` and arithmetic operators.
You can implement these operators for your own `struct`s when you need them.

One thing to note about `TimeSpan` is that it implements a number of interfaces e.g. `IComparable<TimeSpan>`. Although `struct`s cannot be derived from other `struct`s they can implement interfaces.
One thing to note about `TimeSpan` is that it implements a number of interfaces e.g. `IComparable<TimeSpan>`.
Although `struct`s cannot be derived from other `struct`s they can implement interfaces.

## Equality

Equality testing for `struct`s can often be much simpler than that for `class`s as it simply compares fields for equality by default. There is no need to override `object.Equals()` (or `GetHashCode()`). Remember that if you are relying on `Object.GetHashCode()` you must still ensure that the fields involved in generating the hash code (i.e. all the fields) must not change while a hashed collection is use. Effectively, this means that structs used in this way should be immutable.
Equality testing for `struct`s can often be much simpler than that for `class`es as it simply compares fields for equality by default.
There is no need to override `object.Equals()` (or `GetHashCode()`).
Remember that if you are relying on `Object.GetHashCode()` you must still ensure that the fields involved in generating the hash code (i.e. all the fields) must not change while a hashed collection is use.
Effectively, this means that structs used in this way should be immutable.

In contrast to the method, `Equals()`, there is no default implementation of the equality operators, `==` and `!=`. If your `struct` needs them then you will have to implement them.
In contrast to the method, `Equals()`, there is no default implementation of the equality operators, `==` and `!=`.
If your `struct` needs them then you will have to implement them.

On the other hand, this [article][equality] describes how performance can be optimised by creating your own custom `Equals()` and `GetHashCode()` method as is often done with `class`s. The difference in the case of this exercise was about 20% in a not very rigorous comparison but that may be on the low side because all the fields are of the same type - see below.
On the other hand, this [article][equality] describes how performance can be optimised by creating your own custom `Equals()` and `GetHashCode()` method as is often done with `class`es.
The difference in the case of this exercise was about 20% in a not very rigorous comparison but that may be on the low side because all the fields are of the same type - see below.

There are discussions on the [web][equality-performance] about speed improvements, where the `Equals()` method is not overridden, if all fields are of the same type. The difference in this exercise of including disparate fields was about 60%. This is not mentioned in Microsoft's documentation so that makes it an un-documented implementation detail, and it should be exploited judiciously.
There are discussions on the [web][equality-performance] about speed improvements, where the `Equals()` method is not overridden, if all fields are of the same type.
The difference in this exercise of including disparate fields was about 60%.
This is not mentioned in Microsoft's documentation so that makes it an un-documented implementation detail, and it should be exploited judiciously.

```csharp
public bool Equals(Weight other)
Expand Down
4 changes: 3 additions & 1 deletion concepts/structs/introduction.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Introduction

C# `struct`s are closely related `class`s. They have state and behavior. They have constructors that take arguments, instances can be assigned, tested for equality and stored in collections.
C# `struct`s are closely related to `class`es.
They have state and behavior.
They have constructors that take arguments, instances can be assigned, tested for equality and stored in collections.

```csharp
enum Unit
Expand Down

0 comments on commit 0b8b0a3

Please sign in to comment.