Easy Source Generators - Code generation made easy.
With this package, you can easily create code that generates source - without creating a separate Analyzers assembly and without learning Roslyn Source Generators. It will be generated any time you run a build.
Just look at the examples below, or scroll down to a more in-depth explanation.
public enum ColorsEnum { Red, Green, Blue }
public partial class ColorsClass
{
public partial string GetAllColorsString();
[GeneratesMethod(nameof(GetAllColorsString))]
static string GetAllColorsString_Generator() =>
string.Join(", ", Enum.GetNames<ColorsEnum>());
}This generates a method:
public string GetAllColorsString() => "Red, Green, Blue";public static partial class PiExample
{
public static partial int GetPiDecimal(int decimalNumber);
[GeneratesMethod(nameof(GetPiDecimal))]
[SwitchCase(0)]
[SwitchCase(1)]
[SwitchCase(2)]
static int GetPiDecimal_Generator_Specialized(int decimalNumber) =>
SlowMath.CalculatePiDecimal(decimalNumber);
[GeneratesMethod(nameof(GetPiDecimal))]
[SwitchDefault]
static Func<int, int> GetPiDecimal_Generator_Fallback() =>
decimalNumber => SlowMath.CalculatePiDecimal(decimalNumber);
}This generates a method:
public static int GetPiDecimal(int decimalNumber)
{
switch (decimalNumber)
{
case 0: return 3;
case 1: return 1;
case 2: return 4;
default: return CalculatePiDecimal(decimalNumber);
}
}Instead of using attributes, you can use the fluent API to build more complex behaviour:
public enum FourLegged { Dog, Cat, Lizard }
public enum Mammal { Dog, Cat }
public static partial class MapperFluent
{
public static partial Mammal MapToMammal(FourLegged fourLegged);
[GeneratesMethod(nameof(MapToMammal))]
static IMethodImplementationGenerator MapToAnimal_Generator() =>
Generate
.Method().WithParameter<FourLegged>().WithReturnType<Mammal>()
.WithSwitchBody()
.ForCases(GetFourLeggedAnimalsThatHasMatchInMammalAnimal()).ReturnConstantValue(fourLegged => Enum.Parse<Mammal>(fourLegged.ToString(), true))
.ForDefaultCase().UseBody(fourLegged => () => throw new ArgumentException($"Cannot map {fourLegged} to a Mammal"));
static FourLegged[] GetFourLeggedAnimalsThatHasMatchInMammalAnimal() =>
Enum
.GetValues<FourLegged>()
.Where(fourLeggedAnimal => Enum.TryParse(typeof(Mammal), fourLeggedAnimal.ToString(), true, out _))
.ToArray();
}This generates a method:
public static Mammal MapToMammal(FourLegged fourLegged)
{
switch (fourLegged)
{
case FourLegged.Dog: return Mammal.Dog;
case FourLegged.Cat: return Mammal.Cat;
default: throw new ArgumentException($"Cannot map {fourLegged} to a Mammal");
}
}See the full example project here: /EasySourceGenerators.Examples.
You declare partial methods, either static or non-static, and provide generator methods marked with attributes such as:
[GeneratesMethod(nameof(YourMethod)][SwitchCase("someArgumentValue)][SwitchDefault]
The generator uses Roslyn Source Generators under the hood to generate the source at build time.
For more complex behavior there is a fluent API as well (see MapperFluent example above).
The Generators package and its binaries will not be included in your shipped code. The generators package will be added as a compile-time only dependency:
<PackageReference Include="EasySourceGenerators.Generators" Version="x.y.z"
PrivateAssets="all"
IncludeAssets="runtime; build; native; contentfiles; analyzers; buildtransitive" />This project uses Roslyn Source Generators under the hood. This gives you great out-of-the-box support from IDEs like Rider, VSCode, and VisualStudio.
You can browse the generated code live in the IL Viewer window of your IDE:
Remove the guesswork from Source Generators.
Roslyn Source Generator projects often produce errors that are hard to understand. One of the main goals of this package is to make sure that any error - whether it’s a user mistake, a setup problem, or an edge case - shows up clearly in your IDE by highlighting the line that caused it.
The project is split into:
EasySourceGenerators.Abstractions- attributes and fluent interfaces used in consumer codeEasySourceGenerators.Generators- the source generator implementationEasySourceGenerators.Examples- practical usage examplesEasySourceGenerators.Tests- tests with Generators as Roslyn Source GeneratorsEasySourceGenerators.GeneratorTests- tests with Generators as assembly references, to cover tests that would be impossible otherwise