Generates IFormattable
Installation
dotnet add package VoloGen.Formattable
dotnet add package VoloGen.Formattable.Generator
Requirements
The annotated type must:
- Be declared as
partial
- Not be
static
- Define one core method:
bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider? provider) – your formatting logic
- Provide one of the following for
ToString generation:
const int MaxBufferSize – the generator uses stackalloc / ArrayPool<char> to build the string
string ToString(string?, IFormatProvider?) – your own conversion method
Attribute Properties
| Property |
Type |
Default |
Description |
ImplementUtf8 |
bool |
false |
Generate IUtf8SpanFormattable overloads |
DefaultFormat |
string? |
null |
Default format string for formatless overloads |
AllowNullFormatProvider |
bool |
true |
When false, generated overloads throw ArgumentNullException for null providers |
What Gets Generated
Base Overloads (always generated)
| Generated Member |
Delegates To |
string ToString(string? format, IFormatProvider? provider) |
Via MaxBufferSize stackalloc or user’s ToString |
override string ToString() |
ToString(DefaultFormat, null) |
bool ISpanFormattable.TryFormat(...) |
Core TryFormat |
UTF-8 Overloads (ImplementUtf8 = true)
| Generated Member |
Delegates To |
bool TryFormat(Span<byte> utf8Destination, out int bytesWritten, ReadOnlySpan<char> format, IFormatProvider? provider) |
Formats to chars -> encodes to UTF-8 |
When disabled, generated overloads that receive a null IFormatProvider? throw ArgumentNullException before delegating to your core method.
Example
With MaxBufferSize
using VoloGen;
[AutoFormattable(DefaultFormat = "N2")]
public partial struct Currency
{
private readonly decimal _value;
public const int MaxBufferSize = 64;
public Currency(decimal value)
{
_value = value;
}
public bool TryFormat(Span<char> destination, out int charsWritten,
ReadOnlySpan<char> format, IFormatProvider? provider)
{
return _value.TryFormat(destination, out charsWritten, format, provider);
}
}
With Custom ToString
using VoloGen;
[AutoFormattable]
public partial struct Percentage
{
private readonly decimal _value;
public bool TryFormat(Span<char> destination, out int charsWritten,
ReadOnlySpan<char> format, IFormatProvider? provider)
{
return _value.TryFormat(destination, out charsWritten, format, provider);
}
public string ToString(string? format, IFormatProvider? provider)
{
return _value.ToString(format, provider) + "%";
}
}
With All Options
using VoloGen;
[AutoFormattable(ImplementUtf8 = true, DefaultFormat = "C", AllowNullFormatProvider = false)]
public partial struct Money
{
private readonly decimal _amount;
public const int MaxBufferSize = 128;
public bool TryFormat(Span<char> destination, out int charsWritten,
ReadOnlySpan<char> format, IFormatProvider? provider)
{
return _amount.TryFormat(destination, out charsWritten, format, provider);
}
}
Usage
var price = new Currency(1234.567m);
// ToString with default format
Console.WriteLine(price.ToString()); // "1,234.57" (DefaultFormat = "N2")
// ToString with explicit format
Console.WriteLine(price.ToString("C", CultureInfo.GetCultureInfo("en-US"))); // "$1,234.57"
// ISpanFormattable -- TryFormat to a span
Span<char> buffer = stackalloc char[64];
if (price.TryFormat(buffer, out int written, "F1", null))
{
Console.WriteLine(buffer[..written]); // "1234.6"
}
// String interpolation (leverages ISpanFormattable)
Console.WriteLine($"Total: {price:N0}"); // "Total: 1,235"
Diagnostics
| ID |
Trigger |
| VG0002 |
Type is not partial |
| VG0003 |
Type is static |
| VG0007 |
Missing core TryFormat method |
| VG0008 |
Missing both ToString(string?, IFormatProvider?) and MaxBufferSize |