Skip to content

Commit 5697c39

Browse files
Merge pull request #16 from ShawnLaMountain/SoureGenerator
Soure generator
2 parents 00c4785 + 6f9e577 commit 5697c39

41 files changed

Lines changed: 2500 additions & 44 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/Test.yml

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
name: CD
2+
3+
on:
4+
release:
5+
types: [published]
6+
7+
env:
8+
TITLE: "Thread-Safe Objects"
9+
DESCRIPTION: "A combination of generic Thread-Safe objects for .Net development."
10+
TAGS: "thunderdesign visual%2Dstudio c%2Dsharp dotnet%2Dstandard dotnet%2Dframework dotnet%2Dcore cross%2Dplatform pcl%2Dlibrary mono xamarin%2Dforms xamarin%2Dandroid xamarin%2Dios xamarin%2Dmac xamarin%2Duwp unity csharp net dotnet threading bindable binding"
11+
#FILE_NAME: ex: "ThunderDesign.Net-PCL.Threading"
12+
FILE_NAME: "${{ github.event.repository.name }}"
13+
#REPOSITORY_NAME: ex: "ThunderDesign.Net-PCL.Threading"
14+
REPOSITORY_NAME: ${{ github.event.repository.name }}
15+
#REPOSITORY_OWNER: ex: "ThunderDesign"
16+
REPOSITORY_OWNER: ${{ github.repository_owner }}
17+
#GITHUB_URL: ex: "https://github.com/ThunderDesign"
18+
GITHUB_URL: ${{ github.server_url }}/${{ github.repository_owner }}
19+
#REPOSITORY_URL: ex: "https://github.com/ThunderDesign/ThunderDesign.Net-PCL.Threading"
20+
REPOSITORY_URL: ${{ github.server_url }}/${{ github.repository_owner }}/${{ github.event.repository.name }}
21+
22+
PACKAGE_OUTPUT_DIRECTORY: ${{ github.workspace }}\output
23+
24+
jobs:
25+
pack:
26+
27+
runs-on: [windows-2019]
28+
29+
steps:
30+
- name: Checkout
31+
uses: actions/checkout@v2
32+
33+
- name: Setup .NET 2.0
34+
uses: actions/setup-dotnet@v1
35+
with:
36+
dotnet-version: 2.0.x
37+
38+
- name: Setup MSBuild
39+
uses: microsoft/setup-msbuild@v1.1
40+
41+
- name: Setup NuGet
42+
uses: NuGet/setup-nuget@v1.0.5
43+
44+
- name: Restore NuGet packages.sln
45+
run: nuget restore ./src/${{ env.FILE_NAME}}.sln
46+
47+
- name: Build Solution
48+
run: msbuild ./src/${{ env.FILE_NAME}}.sln /p:Configuration=Release
49+
50+
- name: Prepare .nuspec
51+
run: |
52+
$nuspec = Get-Content ThunderDesign.Net-PCL.nuspec.in
53+
$nuspec = $nuspec -replace '\$\{\{ env.FILE_NAME \}\}', '${{ env.FILE_NAME }}'
54+
$nuspec = $nuspec -replace '\$\{\{ env.TITLE \}\}', '${{ env.TITLE }}'
55+
$nuspec = $nuspec -replace '\$\{\{ env.DESCRIPTION \}\}', '${{ env.DESCRIPTION }}'
56+
$nuspec = $nuspec -replace '\$\{\{ env.TAGS \}\}', '${{ env.TAGS }}'
57+
$nuspec = $nuspec -replace '\$\{\{ env.GITHUB_URL \}\}', '${{ env.GITHUB_URL }}'
58+
$nuspec = $nuspec -replace '\$\{\{ env.REPOSITORY_URL \}\}', '${{ env.REPOSITORY_URL }}'
59+
Set-Content ThunderDesign.Net-PCL.nuspec $nuspec
60+
shell: pwsh
61+
62+
- name: Create NuGet Package
63+
run: nuget pack ThunderDesign.Net-PCL.nuspec -Version ${{ github.event.release.tag_name }} -OutputDirectory ${{ env.PACKAGE_OUTPUT_DIRECTORY }}
64+
65+
- name: Archive NuGet Package
66+
uses: actions/upload-artifact@v2.3.1
67+
with:
68+
name: Package_${{ env.FILE_NAME}}.${{ github.event.release.tag_name }}
69+
path: ${{ env.PACKAGE_OUTPUT_DIRECTORY}}\${{ env.FILE_NAME}}.${{ github.event.release.tag_name }}.nupkg

README.md

Lines changed: 136 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,48 @@
1-
# ThunderDesign.Net-PCL.Threading
1+
# ThunderDesign.Net-PCL.Threading
22
[![CI](https://github.com/ThunderDesign/ThunderDesign.Net-PCL.Threading/actions/workflows/CI.yml/badge.svg)](https://github.com/ThunderDesign/ThunderDesign.Net-PCL.Threading/actions/workflows/CI.yml)
33
[![CD](https://github.com/ThunderDesign/ThunderDesign.Net-PCL.Threading/actions/workflows/CD.yml/badge.svg)](https://github.com/ThunderDesign/ThunderDesign.Net-PCL.Threading/actions/workflows/CD.yml)
44
[![Nuget](https://img.shields.io/nuget/v/ThunderDesign.Net-PCL.Threading)](https://www.nuget.org/packages/ThunderDesign.Net-PCL.Threading)
55
[![License](https://img.shields.io/github/license/ThunderDesign/ThunderDesign.Net-PCL.Threading)](https://github.com/ThunderDesign/ThunderDesign.Net-PCL.Threading/blob/main/LICENSE)
6-
[![Net](https://img.shields.io/badge/.net%20standard-v1.0%20--%20v2.1-blue)](https://github.com/ThunderDesign/ThunderDesign.Net-PCL.Threading/blob/main/README.md)
6+
[![NetStandard](https://img.shields.io/badge/.net%20standard-v1.0%20--%20v2.1-blue)](https://github.com/ThunderDesign/ThunderDesign.Net-PCL.Threading/blob/main/README.md)
7+
[![Net](https://img.shields.io/badge/.net%20-v6.0%20--%20v8.0-blue)](https://github.com/ThunderDesign/ThunderDesign.Net-PCL.Threading/blob/main/README.md)
8+
9+
---
710

811
A combination of generic Thread-Safe objects for .Net development.
912

13+
---
14+
15+
<div align="center">
16+
17+
<h2>🚀 <b>Now with .NET 8 support and built-in Source Generators!</b> 🚀</h2>
18+
19+
</div>
20+
21+
> - **.NET 8**: Take advantage of the latest .NET features and performance improvements.
22+
> - **Source Generators**: Eliminate boilerplate and let the library generate thread-safe, bindable properties for you automatically!
23+
>
24+
> _Get started faster, write less code, and enjoy modern .NET development!_
25+
1026
----
1127

1228
A simple C# repository containing a few basic useful Thread-Safe Objects.
1329
### Highlights include:
1430

1531
- Collections
16-
- ObservableDictionaryThreadSafe
17-
- ObservableCollectionThreadSafe
1832
- CollectionThreadSafe
1933
- DictionaryThreadSafe
20-
- SortedListThreadSafe
34+
- HashSetThreadSafe
35+
- LinkedListThreadSafe
2136
- ListThreadSafe
37+
- ObservableCollectionThreadSafe
38+
- ObservableDictionaryThreadSafe
2239
- QueueThreadSafe
40+
- SortedDictionaryThreadSafe
41+
- SortedListThreadSafe
42+
- StackThreadSafe
2343
- DataCollections
24-
- ObservableDataDictionary
2544
- ObservableDataCollection
45+
- ObservableDataDictionary
2646
- DataObjects
2747
- BindableDataObject
2848
- DataObject
@@ -33,10 +53,118 @@ A simple C# repository containing a few basic useful Thread-Safe Objects.
3353
- ObjectExtention
3454
- HelperClasses
3555
- ThreadHelper
56+
- Interfaces
57+
- IBindableCollection
58+
- IBindableDataObject
59+
- IBindableDataObject\<Key>
60+
- IBindableObject
61+
- ICollectionThreadSafe
62+
- IDataObject
63+
- IDataObject\<Key>
64+
- IDictionaryThreadSafe
65+
- IHashSetThreadSafe
66+
- ILinkedListThreadSafe
67+
- IListThreadSafe
68+
- IObservableDataCollection
69+
- IObservableDataCollection\<T>
70+
- ISortedDictionaryThreadSafe
71+
- IStackThreadSafe
3672
- Objects
3773
- BindableObject
3874
- ThreadObject
3975

76+
----
77+
78+
## Source Generators
79+
80+
The `ThunderDesign.Net-PCL.SourceGenerators` project provides Roslyn-based source generators that automate the creation of common boilerplate code for thread-safe and bindable objects in this library. By including this package in your project, you can reduce repetitive code and ensure consistency across your data and collection classes.
81+
82+
### What does it do?
83+
84+
- **Automatic Property Generation:**
85+
The source generator scans your code for fields marked with specific attributes (such as `[BindableProperty]` or `[Property]`) and automatically generates the corresponding properties, including thread-safe accessors and `INotifyPropertyChanged` support where appropriate.
86+
- **Interface Implementation:**
87+
If your class does not already implement interfaces like `IBindableObject`, the generator will add the necessary interface implementations and event wiring.
88+
- **Thread Safety:**
89+
Generated properties use locking patterns to ensure thread safety, matching the patterns used throughout the ThunderDesign.Net-PCL.Threading library.
90+
91+
### How to use
92+
93+
1. **Add the NuGet package:**
94+
Reference the `ThunderDesign.Net-PCL.SourceGenerators` package in your project. If you are building from source, add a project reference to `ThunderDesign.Net-PCL.SourceGenerators.csproj`.
95+
96+
2. **Annotate your fields:**
97+
Use `[BindableProperty]` or `[Property]` attributes on your fields to indicate which properties should be generated. The generator will handle the rest.
98+
99+
3. **Build your project:**
100+
When you build, the source generator will automatically add the generated code to your compilation. You do not need to manually include or maintain the generated files.
101+
102+
4. **Enjoy less boilerplate:**
103+
Your classes will have all the necessary properties, events, and thread-safety mechanisms without manual implementation.
104+
105+
> **Note:** Source generators require Visual Studio 2019 16.9+ or .NET SDK 5.0+ for full support.
106+
107+
### Example Usage
108+
109+
Suppose you want to create a thread-safe, bindable object with automatic property and notification support.
110+
With the source generator, you only need to annotate your fields:
111+
112+
```csharp
113+
using ThunderDesign.Net.Threading.Attributes;
114+
public partial class Person
115+
{
116+
[BindableProperty]
117+
private string _name;
118+
119+
[Property]
120+
private int _age;
121+
}
122+
```
123+
124+
**What gets generated:**
125+
- A public `Name` property with thread-safe getter/setter and `INotifyPropertyChanged` support.
126+
- A public `Age` property with thread-safe getter/setter.
127+
128+
```csharp
129+
using System.ComponentModel;
130+
using System.Runtime.CompilerServices;
131+
using ThunderDesign.Net.Threading.Extentions;
132+
using ThunderDesign.Net.Threading.Interfaces;
133+
134+
public partial class Person : IBindableObject, INotifyPropertyChanged
135+
{
136+
public event PropertyChangedEventHandler PropertyChanged;
137+
138+
protected readonly object _Locker = new object();
139+
140+
public string Name
141+
{
142+
get { return this.GetProperty(ref _name, _Locker); }
143+
set { this.SetProperty(ref _name, value, _Locker, true); }
144+
}
145+
146+
public int Age
147+
{
148+
get { return this.GetProperty(ref _age, _Locker); }
149+
set { this.SetProperty(ref _age, value, _Locker); }
150+
}
151+
}
152+
```
153+
154+
You can now use your `Person` class like this:
155+
156+
```csharp
157+
var person = new Person();
158+
person.Name = "Alice";
159+
person.Age = 30; // PropertyChanged event will be raised for Name changes if you subscribe to it.
160+
```
161+
162+
163+
**No need to manually implement** property notification, thread safety, or boilerplate code—the generator does it for you!
164+
165+
> For more advanced scenarios, you can use attribute parameters to control property behavior (e.g., read-only, also notify other properties, etc.).
166+
167+
40168
----
41169

42170
## Installation
@@ -74,4 +202,5 @@ This can be overwritten durring creation or by setting Property `WaitOnNotifyCol
74202

75203
Observable Objects Property `WaitOnNotifyPropertyChanged` has been renamed to Property `WaitOnNotifying`.
76204

77-
Observable Collections Property `WaitOnNotifyCollectionChanged` has been removed and now uses Property `WaitOnNotifying`.
205+
Observable Collections Property `WaitOnNotifyCollectionChanged` has been removed and now uses Property `WaitOnNotifying`.
206+
----

samples/Xamarin/SimpleBinding/SimpleBinding.Android/Resources/Resource.designer.cs

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

samples/Xamarin/SimpleContacts/SimpleContacts.Android/Resources/Resource.designer.cs

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

samples/Xamarin/SimpleContacts/SimpleContacts.sln

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,14 @@ EndProject
88
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SimpleContacts.iOS", "SimpleContacts.iOS\SimpleContacts.iOS.csproj", "{C1F8D9DD-88FB-42E3-A3A1-01F2554FFD1B}"
99
EndProject
1010
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SimpleContacts", "SimpleContacts\SimpleContacts.csproj", "{42D29358-CA82-4C55-9B3D-D8AB994C0FDC}"
11+
ProjectSection(ProjectDependencies) = postProject
12+
{C0A3769B-4580-2360-A1DF-C2A16B56DBF2} = {C0A3769B-4580-2360-A1DF-C2A16B56DBF2}
13+
EndProjectSection
1114
EndProject
1215
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThunderDesign.Net-PCL.Threading", "..\..\..\src\ThunderDesign.Net-PCL.Threading\ThunderDesign.Net-PCL.Threading.csproj", "{8616AAA2-E21C-4D85-BE38-4124A58ECA97}"
1316
EndProject
17+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ThunderDesign.Net-PCL.SourceGenerators", "..\..\..\src\ThunderDesign.Net-PCL.SourceGenerators\ThunderDesign.Net-PCL.SourceGenerators.csproj", "{C0A3769B-4580-2360-A1DF-C2A16B56DBF2}"
18+
EndProject
1419
Global
1520
GlobalSection(SolutionConfigurationPlatforms) = preSolution
1621
Debug|Any CPU = Debug|Any CPU
@@ -87,6 +92,18 @@ Global
8792
{8616AAA2-E21C-4D85-BE38-4124A58ECA97}.Release|iPhone.Build.0 = Release|Any CPU
8893
{8616AAA2-E21C-4D85-BE38-4124A58ECA97}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
8994
{8616AAA2-E21C-4D85-BE38-4124A58ECA97}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
95+
{C0A3769B-4580-2360-A1DF-C2A16B56DBF2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
96+
{C0A3769B-4580-2360-A1DF-C2A16B56DBF2}.Debug|Any CPU.Build.0 = Debug|Any CPU
97+
{C0A3769B-4580-2360-A1DF-C2A16B56DBF2}.Debug|iPhone.ActiveCfg = Debug|Any CPU
98+
{C0A3769B-4580-2360-A1DF-C2A16B56DBF2}.Debug|iPhone.Build.0 = Debug|Any CPU
99+
{C0A3769B-4580-2360-A1DF-C2A16B56DBF2}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
100+
{C0A3769B-4580-2360-A1DF-C2A16B56DBF2}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
101+
{C0A3769B-4580-2360-A1DF-C2A16B56DBF2}.Release|Any CPU.ActiveCfg = Release|Any CPU
102+
{C0A3769B-4580-2360-A1DF-C2A16B56DBF2}.Release|Any CPU.Build.0 = Release|Any CPU
103+
{C0A3769B-4580-2360-A1DF-C2A16B56DBF2}.Release|iPhone.ActiveCfg = Release|Any CPU
104+
{C0A3769B-4580-2360-A1DF-C2A16B56DBF2}.Release|iPhone.Build.0 = Release|Any CPU
105+
{C0A3769B-4580-2360-A1DF-C2A16B56DBF2}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
106+
{C0A3769B-4580-2360-A1DF-C2A16B56DBF2}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
90107
EndGlobalSection
91108
GlobalSection(SolutionProperties) = preSolution
92109
HideSolutionNode = FALSE

samples/Xamarin/SimpleContacts/SimpleContacts/SimpleContacts.csproj

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
<Project Sdk="Microsoft.NET.Sdk">
1+
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
44
<TargetFramework>netstandard2.0</TargetFramework>
55
<ProduceReferenceAssembly>true</ProduceReferenceAssembly>
6+
<LangVersion>9.0</LangVersion>
67
</PropertyGroup>
78

89
<ItemGroup>
@@ -25,4 +26,12 @@
2526
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
2627
</EmbeddedResource>
2728
</ItemGroup>
29+
30+
<ItemGroup>
31+
<None Include="$(TargetPath)" Pack="true" PackagePath="analyzers/dotnet/cs/" />
32+
</ItemGroup>
33+
34+
<ItemGroup>
35+
<Analyzer Include="..\..\..\..\src\ThunderDesign.Net-PCL.SourceGenerators\bin\Debug\netstandard2.0\ThunderDesign.Net-PCL.SourceGenerators.dll" />
36+
</ItemGroup>
2837
</Project>
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.ComponentModel;
4+
using System.Text;
5+
using ThunderDesign.Net.Threading.Extentions;
6+
using ThunderDesign.Net.Threading.Objects;
7+
using ThunderDesign.Net_PCL.Threading.Attributes;
8+
9+
namespace SimpleContacts.ViewModels
10+
{
11+
internal partial class TestModel : INotifyPropertyChanged
12+
{
13+
public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
14+
private void Test()
15+
{
16+
this.LastName = "John";
17+
}
18+
19+
//public void OnPropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string propertyName = "")
20+
//{
21+
// this.NotifyPropertyChanged(PropertyChanged, propertyName);
22+
//}
23+
24+
[BindableProperty(threadSafe:false,notify:false, alsoNotify: new string[] { "FullName" })]
25+
private string _FirstName = String.Empty;
26+
27+
[BindableProperty(alsoNotify: new string[] { "FullName" })]
28+
private string _lastName = String.Empty;
29+
30+
[Property(readOnly: true, threadSafe: false)]
31+
private string _MiddleName = String.Empty;
32+
33+
//private string FullName => $"{LastName}, {FirstName} {MiddleName}";
34+
//protected readonly object _Locker = new object();
35+
}
36+
}

0 commit comments

Comments
 (0)