PartialSourceGen 0.0.11

There is a newer version of this package available.
See the version list below for details.
dotnet add package PartialSourceGen --version 0.0.11
NuGet\Install-Package PartialSourceGen -Version 0.0.11
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="PartialSourceGen" Version="0.0.11" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add PartialSourceGen --version 0.0.11
#r "nuget: PartialSourceGen, 0.0.11"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install PartialSourceGen as a Cake Addin
#addin nuget:?package=PartialSourceGen&version=0.0.11

// Install PartialSourceGen as a Cake Tool
#tool nuget:?package=PartialSourceGen&version=0.0.11

What is it?

This is a package that generates a partial entity from a model that has the attribute Partial.

The package is inspired by the typescript generic type Partial which converts all the properties of an entity into optional properties.

Example:

Input model: Person.cs

using System;
using PartialSourceGen;

namespace MySpace;

[Partial]
public record Person
{
    public int ID { get; init; }
    public string Name { get; init; }
}

The output: PartialPerson.g.cs

#nullable enable
using System;
using PartialSourceGen;

namespace MySpace;

public partial record PartialPerson
{
    public int? ID { get; init; }
    public string? Name { get; init; }
}

Installation

Add nuget package dotnet add package PartialSourceGen to your project and ensure that the csproj reference the package as an analyzer/source generator by having:

<ItemGroup>
    <PackageReference Include="PartialSourceGen" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
</ItemGroup>

Why

When you have an API that takes in some model, but you don't need to specify all the properties, you can just use this library.
OR you can just write the partial model yourself.

The advantage with source generated models is that this will be in-sync with your actual model without requiring you to
update both the actual model and the partial model every time you make changes to the actual model.

Example:

// web api endpoint
app.MapPost("/update/person", async (PartialPerson updates) =>
{
    // Only the values that are set, in updates have values, the rest are null
    // work: update person
});

Conventions and settings

The generated model can be fine tuned by the PartialAttribute parameters.

Custom summary

The partial entity can have a custom summary by specifying the Summary property like so:

using PartialSourceGen;

namespace MyNameSpace;

[Partial(Summary = "My custom summary for the partial entity")]
public record Model
{
    public int ID { get; init; }
}

Custom generated entity name

The partial entity can have a custom name by specifying the PartialClassName property like so:

using PartialSourceGen;

namespace MyNameSpace;

[Partial(PartialClassName = "MyPartialModel")]
public record Model
{
    public int ID { get; init; }
}

Be carefull the generated model does not sanitize input, therefore be sure that the name you give is a valid C# object name.

The usage of the generated output will be:

MyPartialModel model = new()
{
    ID = 123
};

// Prints: Model ID: 123
Console.WriteLine("Model ID: {0}", model.ID.GetValueOrDefault());

Include required properties

If the model contains properties that are required, they will be made optional by default and nullable.
If you want to keep the required modifier, you can specify IncludeRequiredProperties, like so:

using PartialSourceGen;

namespace MyNameSpace;

[Partial(IncludeRequiredProperties = true)]
public record Model
{
    public required int ID { get; init; }
}

Then when constructing the partial entity, you must include the required properties!

PartialModel model = new()
{
    // Must include ID
    // when initializing PartialModel
    ID = 123
};

// Prints: Model ID: 123
Console.WriteLine("Model ID: {0}", model.ID);

Note:
That required properties can be set either via using the keyword required or an attribute Required. When including properties that are marked as required, the property will not be made nullable. They will retain their original property type, thus if the property was nullable the required property will also be nullable.

Add custom methods to the partial entity

The generated class/struct/record is a partial entity, thus it is possible to just add a method in a separate file.
The normal constraints and rules apply for partial classes: https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/partial-classes-and-methods

Example:

// Person.cs
using PartialSourceGen;

namespace People;

[Partial]
record Person
{
    int Age { get; }
}

Add custom method:

// PartialPerson.cs
using System;

record partial PartialPerson
{
    int AgeInDogYears()
    {
        return Age * 7;
    }
}

Fine tune properties using attributes

Include property initializer

A property initializer in the partial entity can be included by annotating the property with IncludeInitializer attribute.

Example:

Input Person.cs

[Partial]
public record Person
{
    [IncludeInitializer]
    public string Name { get; set; } = string.Empty;
}

Would produce PartialPerson.g.cs:

public record PartialPerson
{
    public string? Name { get; set; } = string.Empty;
}

The default behaviour is to exclude property initializers.

Reference partial other partial entities

To reference another partial object, add the PartialReference attribute to the property.

If using c# 11.0 (dotnet 7.0 or newer) you can use the generic version, like so:

// Person.cs
using PartialSourceGen;

namespace MySpace;

[Partial]
public record Person
{
    [PartialReference<Post, PartialPost>("CustomOptionalNameForPosts")]
    public List<Post> Posts { get; set; } = [];
}

Which will generate:

// PartialPerson.g.cs
using PartialSourceGen;

namespace MySpace;

public record PartialPerson
{
    public List<PartialPost>? CustomOptionalNameForPosts { get; set; }
}

If no name is included the original name will be used.

If using an older version than C# 11.0, you can use the non-generic attribute version:

// Person.cs
using PartialSourceGen;

namespace MySpace;

[Partial]
public record Person
{
    [PartialReference(typeof(Post), typeof(PartialPost))]
    public List<Post> Posts { get; set; } = [];
}

Functionalities

This source generator will do the following:

  • If the input class has type constraints for a generic type, with notnull. This will be removed in the partial class.
  • If the property is marked with a required keyword, or a required attribute. The type will be unchanged.
  • Any methods or fields that are referenced from a property will be included in the partial class
  • If the input is a struct, and contains property initializers then all the constructors and their references to fields and methods will be included.

References

Future improvements / ideas

  • Does this work in a large project? Using IIncrementalSourceGenerator should be faster for the IDE? I don't know.
  • Somehow add a custom method to the generated partial entity that can create the actual model with default values for the missing properties.
  • What about conflicting classes or files? Not currently handled
  • Currently does not check if Required attribute comes from any particular namespace.
There are no supported framework assets in this package.

Learn more about Target Frameworks and .NET Standard.

  • .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.0.16 59 5/14/2024
0.0.15 338 4/6/2024
0.0.14 127 4/6/2024
0.0.13 117 4/5/2024
0.0.12 121 4/5/2024
0.0.11 128 4/4/2024
0.0.10 122 4/4/2024
0.0.9 128 4/4/2024
0.0.8 122 4/3/2024
0.0.7 143 4/2/2024
0.0.6 105 4/2/2024
0.0.5 94 4/2/2024
0.0.4 134 4/1/2024
0.0.3 147 4/1/2024
0.0.2 157 3/31/2024
0.0.1 141 3/31/2024