You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+26Lines changed: 26 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -2,6 +2,32 @@
2
2
3
3
A library that automatically adds support for object deconstruction in C#.
4
4
5
+
## Getting Started
6
+
7
+
First, reference the `AutoDeconstruct`[NuGet package](https://www.nuget.org/packages/AutoDeconstruct).
8
+
9
+
Then, add `[AutoDeconstuct]` to a type so you can deconstruct it:
10
+
11
+
```c#
12
+
usingAutoDeconstruct;
13
+
14
+
[AutoDeconstruct]
15
+
publicsealedclassPerson
16
+
{
17
+
publicuintAge { get; set; }
18
+
publicrequiredstringName { get; set; }
19
+
}
20
+
21
+
varperson=newPerson { Age=22, Name="Joe" };
22
+
var (age, name) =person;
23
+
```
24
+
25
+
Read [the overview document](docs/Overview.md) for further details.
26
+
27
+
### Prerequisites
28
+
29
+
The Rocks package targets .NET Standard 2.0 for host flexibility.
30
+
5
31
## Overview
6
32
7
33
The idea started with [this tweet](https://twitter.com/buhakmeh/status/1462106117564207104) - specifically, [this reply](https://twitter.com/dave_peixoto/status/1462181358248374278). I thought...how automatic can I make object deconstruction in C#? That's what this source generator is all about.
Copy file name to clipboardExpand all lines: changelog.md
+5Lines changed: 5 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -5,6 +5,11 @@ All notable changes to this project will be documented in this file.
5
5
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
8
+
## [1.1.0] - 2025.02.01
9
+
10
+
### Added
11
+
- AutoDeconstruct no longer automatically scans for types; `[AutoDeconstruct]` must be used (this improves source generator performance) (issue [#16](https://github.com/JasonBock/AutoDeconstruct/issues/16))
The idea started with [this tweet](https://twitter.com/buhakmeh/status/1462106117564207104) - specifically, [this reply](https://twitter.com/dave_peixoto/status/1462181358248374278). I thought...how automatic can I make object deconstruction in C#? That's what this source generator is all about.
4
12
5
13
## What is a Deconstructor?
6
14
7
-
Object deconstruction was added in C# 7.0. The documentation is [here](https://github.com/dotnet/roslyn/blob/main/docs/features/deconstruction.md), and there's another article [here](https://docs.microsoft.com/en-us/dotnet/csharp/fundamentals/functional/deconstruct#user-defined-types). Basically, a deconstructor can be defined on either a type or as an extension method. In both cases, it has to be named "Deconstruct", it has to return `void`, and all of its parameters must be `out` parameters (the exception is with the extension method, where the first parameter is the object being extended). Furthermore, you can overload `Deconstruct` methods, but all `Deconstruct` methods must have a unique number of `out` parameters. Here are two examples:
15
+
Object deconstruction was added in C# 7.0. The documentation is [here](https://github.com/dotnet/roslyn/blob/main/docs/features/deconstruction.md), and there's another article [here](https://docs.microsoft.com/en-us/dotnet/csharp/fundamentals/functional/deconstruct#user-defined-types). Basically, a deconstructor can be defined on either a type or as an extension method. In both cases, it has to be named "Deconstruct", it has to return `void`, and all of its parameters must be `out` parameters (the exception is with the extension method, where the first parameter is the type being extended). Furthermore, `Deconstruct()` methods can overloaded, but all `Deconstruct()` methods must have a unique number of `out` parameters. Here are two examples:
8
16
9
17
```csharp
10
18
usingSystem;
@@ -43,13 +51,17 @@ var point = new Point(2, 3);
43
51
var (x, y) =point;
44
52
```
45
53
54
+
Note that what values are deconstructed is up to the developer. That is, deconstruction does not require one to deconstruct all property or field values.
55
+
46
56
## AutoDeconstruct Features
47
57
48
-
AutoDeconstruct finds all type and method definitions, and it'll look to see if the type has any `Deconstruct` methods, either as instance or extension methods. If none exist, then AutoDeconstruct looks to see how many public, readable, instance properties exist. If there's at least 1, the library generates a `Deconstruct` extension method in a static class defined in the same namespace as the target type. For example, if we have our `Point` type defined like this:
58
+
### Marking Types
59
+
AutoDeconstruct looks to see if the target type has any `Deconstruct()` methods, either as instance or extension methods (if extension methods are searched for - this is discussed later in this document). If none exist, then AutoDeconstruct looks to see how many accessible, readable, instance properties exist. If there's at least 1, the library generates a `Deconstruct()` extension method in a static class defined in the same namespace as the target type. For example, if we have our `Point` type defined like this:
49
60
50
61
```csharp
51
62
namespaceMaths.Geometry;
52
63
64
+
[AutoDeconstruct]
53
65
publicstructPoint
54
66
{
55
67
publicPoint(intx, inty) =>
@@ -75,29 +87,26 @@ namespace Maths.Geometry
75
87
}
76
88
```
77
89
78
-
If the target type is a reference type, a null check will be generated. Furthermore, the `Deconstruct` extension method will also be created if a `Deconstruct` doesn't exist with the number of properties found. For example, let's say we have this:
90
+
If the target type is a reference type, a null check will be generated. Furthermore, the `Deconstruct()` extension method will also be created if a `Deconstruct()` doesn't exist with the number of properties found. For example, let's say we have this:
AutoDeconstruct would see that there are three properties that could be used for a generated `Deconstruct`. The two `Deconstruct` methods that exist have one and two `out`parameters, so it will generate one that has all three properties as `out` parameters:
109
+
AutoDeconstruct would see that there are three properties that could be used for a generated `Deconstruct()`. The `Deconstruct()` method that exists has one `out`parameter, so it will generate one that has all three properties as `out` parameters:
101
110
102
111
```csharp
103
112
#nullable enable
@@ -115,19 +124,82 @@ namespace Models
115
124
}
116
125
```
117
126
118
-
While AutoDeconstruct will do a complete search for types to generate `Deconstruct` methods, a user may want to opt out of this search for specific types. Adding the `[NoAutoDeconstruct]` attribute to a type will tell AutoDeconstrct to ignore it:
127
+
### Assembly-Level Support
128
+
129
+
`[AutoDeconstruct]` can also be defined at the assembly level to inform AutoDeconstruct to add `Deconstruct()` extension methods for **every** type in the assembly:
130
+
131
+
```csharp
132
+
usingAutoDeconstruct;
133
+
134
+
[assembly: AutoDeconstruct]
135
+
136
+
namespaceModels;
137
+
138
+
publicsealedclassPerson
139
+
{
140
+
publicuintAge { get; init; }
141
+
publicGuidId { get; init; }
142
+
publicstringName { get; init; }
143
+
144
+
publicvoidDeconstruct(outGuidid) =>
145
+
id=this.Id;
146
+
}
147
+
```
148
+
149
+
While AutoDeconstruct will search the target type to see if an existing `Deconstruct()` method exists that matches what AutoDeconstruct would do, a user may want to opt int to a search to look through the entire assembly for `Deconstruct()` extension methods. By default, this is turned off as it's not common to create deconstruction methods this way, but if this completeness is desired, `SearchForExtensionMethods.Yes` can be passed into `[AutoDeconstruct]`:
In this case, AutoDeconstruct will detect an existing `Deconstruct()` method that already does what AutoDeconstruct would generate, so no code is generated. This search flag also works when `[AutoDeconstruct]` is defined on a specific type.
176
+
177
+
### Ignore Deconstruction Creation
178
+
179
+
The `[NoAutoDeconstruct]` attribute can be added to a type will tell AutoDeconstrct to ignore it. Note that this is only relevant when `[AutoDeconstruct]` is added at the assembly level:
119
180
120
181
```csharp
121
182
namespaceAutoDeconstruct;
122
183
namespaceModels;
123
184
185
+
[assembly: AutoDeconstruct]
186
+
124
187
[NoAutoDeconstruct]
125
188
publicsealedclassPerson
126
189
{
127
190
publicuintAge { get; init; }
128
191
publicGuidId { get; init; }
129
192
publicstringName { get; init; }
130
193
}
194
+
195
+
publicstructPoint
196
+
{
197
+
publicPoint(intx, inty) =>
198
+
(this.X, this.Y) = (x, y);
199
+
200
+
publicintX { get; }
201
+
publicintY { get; }
202
+
}
131
203
```
132
204
133
-
In this case, AutoDeconstruct will not generate a `Deconstruct` method for `Person`.
205
+
In this case, AutoDeconstruct will not generate a `Deconstruct` method for `Person`, but it will for `Point`. If a type has `[AutoDeconstruct]` and `[NoAutoDeconstruct]`, `[AutoDeconstruct]` "wins".
* DONE - I added `internal` properties to the list, as it's possible someone may want to deconstruct internally. But, now I need to make the static class and the extension method `internal` if either the target type is `internal`, or any of the properties are `internal`.
3
3
* DONE - Finding matching `Deconstruct()` extension methods isn't correct. We need to also look at the parameter types.
4
4
* DONE - I think I overdid it. If the `Deconstruct()` has the same number of property as parameters, then it has to be excluded, because deconstruct methods can't be overloaded with the same number of parmaters.
@@ -8,7 +8,7 @@
8
8
* DONE - Put a test in to show that a `Deconstruct()` is made even if both attributes exist on the type.
9
9
* DONE - Consider making the generated extension method part of the type declaration if the type is `partial`. See this for details: https://stackoverflow.com/questions/68906372/roslyn-analyzer-is-class-marked-as-partial
10
10
* DONE - Add code to change the name of extension type if there is a collision
11
-
* Add a flag to `[AutoDeconstruct]` to only do a full assembly search of extension method, something like `[AutoDeconstruct(SearchForExtensionMethods.Yes)]`. It would be `SearchForExtensionMethods.No` by default, you need to opt-in to do the search. Most of the time, the search is unnecessary.
11
+
*DONE - Add a flag to `[AutoDeconstruct]` to only do a full assembly search of extension method, something like `[AutoDeconstruct(SearchForExtensionMethods.Yes)]`. It would be `SearchForExtensionMethods.No` by default, you need to opt-in to do the search. Most of the time, the search is unnecessary.
0 commit comments