Monify 1.4.0
dotnet add package Monify --version 1.4.0
NuGet\Install-Package Monify -Version 1.4.0
<PackageReference Include="Monify" Version="1.4.0"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> </PackageReference>
<PackageVersion Include="Monify" Version="1.4.0" />
<PackageReference Include="Monify"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> </PackageReference>
paket add Monify --version 1.4.0
#r "nuget: Monify, 1.4.0"
#:package Monify@1.4.0
#addin nuget:?package=Monify&version=1.4.0
#tool nuget:?package=Monify&version=1.4.0
Monify

Monify, a .NET Roslyn source generator, automates the creation of strongly-typed wrappers around single values, improving semantic clarity, type safety, and maintainability.
It is particularly useful for engineers implementing encapsulated types in functional-style codebases (for example, lightweight monadic wrappers), where eliminating repetitive boilerplate makes experimentation and adoption easier.
Requirements
- C# v2.0 or later.
- Visual Studio 2022 v17.4 or later, or any compatible IDE that supports Roslyn source generators.
Installation
To install Monify, use the following command in your package manager console:
install-package Monify
Evaluating Monify for encapsulated monads
If you are exploring monad-style wrappers for domain modeling, start with the short onboarding guide: Monads with Monify.
The guide includes:
- A practical
ResultCodewrapper example. - A lightweight
MapandBindpattern built on generated conversions. - A
LINQquery expression example (Select/SelectMany) to show composability. - Team-adoption notes for object-oriented and functional mixed codebases.
Usage
Monify turns a class, record, or struct into a strongly typed wrapper around a single value. To opt in, annotate a partial type with the Monify attribute and specify the encapsulated value type.
using Monify;
[Monify<int>]
public partial struct Age;
For language versions earlier than C# 11:
using Monify;
[Monify(Type = typeof(int))]
public partial struct Age;
Generated Members
When applied, Monify generates the boilerplate needed for a lightweight value object:
- A private readonly field
_valuethat stores the encapsulated value. - A constructor accepting the underlying value:
Age(int value). - Implicit conversion operators to and from the encapsulated type.
- Implementations of
IEquatable<Age>andIEquatable<int>. - Equality (
==) and inequality (!=) operators for comparing with other instances or with the underlying value. - Overrides of
Equals(object),GetHashCode(), andToString().
Example
Age age = 42; // implicit conversion from int
int value = age; // implicit conversion to int
if (age == value)
{
// comparisons work with both Age and int
}
Why engineers building monads care
When a team starts introducing monadic patterns, wrappers often begin as tiny domain concepts (Age, EmailAddress, Currency) and quickly grow into chains of encapsulated types. The friction is not in the concept; it is in the repeated constructor, conversion, and equality plumbing.
Monify addresses that friction directly by generating the repetitive mechanics while preserving explicit domain types in your public API. That keeps your codebase readable to object-oriented developers while still supporting functional composition techniques.
Use Monify when you want to:
- Make functional-style value wrappers approachable for engineers new to monads.
- Keep encapsulation and type safety without paying boilerplate costs.
- Evolve from simple wrappers to nested wrapper hierarchies without hand-written conversion glue.
Adoption path for engineering teams
- Start with one obvious value object (
EmailAddress,OrderId, orResultCode). - Add a tiny composition layer (
Map,Bind) in your own domain namespace. - Introduce query-expression support only when the team is ready.
- Gradually expand to nested wrappers as domain boundaries become clearer.
This stepwise path helps teams gain the safety and readability of encapsulated types without requiring an immediate full functional-programming rewrite.
Classes annotated with Monify are sealed automatically to preserve immutability. Types must be partial and cannot declare additional state; the included analyzers will warn when these guidelines are not followed.
Nested wrappers and circular guards
Monify also follows chains of nested wrappers and automatically emits the necessary implicit conversions so the outermost wrapper can convert directly to and from the innermost value type. For example, if Money wraps Amount and Amount wraps decimal, conversions will be generated for every hop, allowing callers to cast Money to decimal (and vice versa) without manual glue code.
To keep the generator safe, conversion discovery halts as soon as a type repeats in the chain. This prevents circular relationships (e.g. Outer wrapping Inner while Inner wraps Outer) from producing infinite loops or ambiguous operators while still supporting arbitrarily deep, non-circular nesting.
Analyzers
Monify includes several analyzers to assist engineers with its usage. These are:
| Rule ID | Category | Severity | Notes |
|---|---|---|---|
| MONFY01 | Usage | Warning | Type is not compatible with Monify |
| MONFY02 | Usage | Warning | Type is not Partial |
| MONFY03 | Design | Error | Type captures State |
| MONFY04 | Design | Error | Self Referencing Type |
Contributing
Contributions are welcome - see the CONTRIBUTING.md file for details.
License
This project is licensed under the MIT License - see the LICENSE.md file for details.
| 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. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.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
- Microsoft.CodeAnalysis.Analyzers (>= 3.11.0 && < 3.12.0)
- System.Collections.Immutable (>= 10.0.8)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.