SettableOnceProperty 0.1.5
dotnet add package SettableOnceProperty --version 0.1.5
NuGet\Install-Package SettableOnceProperty -Version 0.1.5
<PackageReference Include="SettableOnceProperty" Version="0.1.5" />
paket add SettableOnceProperty --version 0.1.5
#r "nuget: SettableOnceProperty, 0.1.5"
// Install SettableOnceProperty as a Cake Addin #addin nuget:?package=SettableOnceProperty&version=0.1.5 // Install SettableOnceProperty as a Cake Tool #tool nuget:?package=SettableOnceProperty&version=0.1.5
SettableOnceProperty
Motivation
While playing with .Net built-in Depency Injection (D.I.), I found myself needing to set some properties of some newly created objects by D.I. mechanism.
But some of such properties needed to be set
only once through runtime lifetime.
Since I have a lot of those properties, I ended up choosing to use the new .Net Incremental Source Generator tool to do so.
Here is what I came up with.
Description
This package use an Incremental Source Generator underneath to augment classes with settable maximum n
times properties.
When appropriately marked, such properties use an hidden SettableNTimesProperty<T>
generic class that encapsulate a T
property while keeping track of how many times it was set
, and nullify any extra set
calls beyond maximum limit, limit that you can provide via an Attribute
.
Usage
If you want to mark a property being settable max n
times, you have to follow thoses rules :
Define such properties inside an
interface
add
using SetOnceGenerator;
namespaceAdd above such properties either
[SetOnce]
attribute or[SetNTimes(n)]
attribueOn any concrete classes that implement that given
interface
, make sure to modify it to bepartial
Optionally, you can add your own logic to handle warnings when trying to get or set the property extending
SettableNTimesProperty.GetWarning()
andSettableNTimesProperty.SetWarning()
method
Example
Lets say you have this DTO class :
internal class DTO
{
int ID { get; init; }
string Name { get; init; }
public DTO(int id, string name = "Default_DTO_Name")
{
ID = id;
Name = name;
}
}
In order to make its properties settable only once instead of using init
, modify your code this way :
internal partial class DTO : IDTO
{
public DTO(int id, string name = "Default_DTO_Name")
{
((IDTO)this).ID = id;
((IDTO)this).Name = name;
}
}
and add this interface
using SetOnceGenerator;
public interface IDTO
{
[SetOnce]
int ID { get; set; }
[SetOnce]
string Name { get; set; }
}
If you want to allow multiple set
, up to n
times maximum, use [SetNTimes(n)]
attribute instead of [SetOnce]
Optional warning handling
By default, nothing warn you when you try to
Get
a non already setted propertySet
an already maximum setted property
You can handle this with your own logic by uncommenting and extending the provided partial class SettableNTimesProperty
, found in your project directory under the automatically created "Custom_Warning" folder.
You can modify the 2 provided partial methods, GetWarning()
and SetWarning()
to do so.
SettableNTimesProperty
class also expose 2 private fields you can use to customize your warning :
`_propertyName`` the name of the property
_maximumSettableTimes
the maximum settable times this property can be setted
For example :
partial void GetWarning()
{
Console.WriteLine($"{_propertyName} hasn't been set yet ! (returning default value instead)");
}
partial void SetWarning()
{
Console.WriteLine($"{_propertyName} has already reach its maximum ({_maximumSettableTimes}) settable times.");
}
Disable automatic copy of Custom_Warnings folder
If you don't wan't to handle you custom logic of Get
and Set
warning, and allow to remove the automatically generated Custom_Warnings folder and SettableNTimesProperty
class, then you can edit your .csproj file to set RefreshCopy
to false
:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<RootNamespace>Testing_SetOncePackage</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<RefreshCopy>False</RefreshCopy>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="SettableOnceProperty" Version="0.1.3" />
</ItemGroup>
</Project>
Embedding attributes
Following Andrew Lock [https://andrewlock.net/creating-a-source-generator-part-8-solving-the-source-generator-marker-attribute-problem-part2/] tutorial,
I ended up using a public attributes DLL to store and share my [SetNTimes(n)]
and [SetOnce]
attributes,
still alowing to automatically generate and embed those attributes in consuming project assembly by setting
SET_ONCE_GENERATOR_EMBED_ATTRIBUTES
MS-Build variable in your .csproj
consuming project properties :
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<LangVersion>latest</LangVersion>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<DefineConstants>SET_ONCE_GENERATOR_EMBED_ATTRIBUTES</DefineConstants>
</PropertyGroup>
</Project>
Excluding generated SettableNTimesProperty<T>
The backbone of those decorated properties to be set up to n
times is in the automatically generated and embedded
SettableNTimesProperty<T>
partial class. If you prefer to exclude it and furnish your own implementation of this partial class,
you can define SET_ONCE_GENERATOR_EXCLUDE_SETTABLE_N_TIMES_PROPERTY
MS-Build variable in your .csproj
consuming project properties :
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<LangVersion>latest</LangVersion>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<DefineConstants>SET_ONCE_GENERATOR_EXCLUDE_SETTABLE_N_TIMES_PROPERTY</DefineConstants>
</PropertyGroup>
</Project>
Note
I first used a bool backend field to manage this but ended up generalising it to be settable n
times.
Even though this is now the underneath mechanism , I kept naming it SettableOnceProperty, since I suppose it is the most common scenario, and what people are looking for.
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
.NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
.NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
.NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
MonoAndroid | monoandroid was computed. |
MonoMac | monomac was computed. |
MonoTouch | monotouch was computed. |
Tizen | tizen40 was computed. tizen60 was computed. |
Xamarin.iOS | xamarinios was computed. |
Xamarin.Mac | xamarinmac was computed. |
Xamarin.TVOS | xamarintvos was computed. |
Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated |
---|---|---|
0.1.5 | 111 | 7/12/2024 |
Handle multiple/cross projects types when generating settableNtimes properties and ensure "using SetOnceGenerator" is always added to generated files. Code has been refactored