Search code examples
typesconstraintsroslyn

Roslyn: How to create generic method type constraints


I have some code like this (using LinqPad):

using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;

void Main()
{
    var cd = ClassDeclaration($"TestExtensions")
        .AddModifiers(Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.StaticKeyword));

    var method =
        MethodDeclaration(ParseTypeName($"T"), $"SetTest")
           .AddModifiers(Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.StaticKeyword))
           .AddTypeParameterListParameters(TypeParameter(Identifier("T")))
           .AddParameterListParameters(
               Parameter(Identifier("definition")).WithType(ParseTypeName("T")).AddModifiers(Token(SyntaxKind.ThisKeyword)),
                Parameter(Identifier("value")).WithType(ParseTypeName("int"))
            )
            .AddConstraintClauses(TypeParameterConstraintClause("T").WithConstraints(GetSL()))
            .WithBody(Block(ParseStatement($"definition.SetField(\"test\", value);"), ParseStatement("return definition;")));

    cd = cd.AddMembers(method);

    // namespace
    var ns = SyntaxFactory
        .NamespaceDeclaration(ParseName("MyNS"))
        .AddMembers(cd);

    var cu = SyntaxFactory.CompilationUnit();

    var code = cu.AddMembers(ns)
        .NormalizeWhitespace()
        .ToFullString();

    // hack because I can't make .WithConstraints work
    //      code = code.Replace("where T :", $"where T : {t.Name}");

    code.Dump();
}

SeparatedSyntaxList<TypeParameterConstraintSyntax> GetSL()
{
    var list = SeparatedList<TypeParameterConstraintSyntax>();
    list.Add(TypeConstraint(ParseTypeName($"Test")));
    return list;
}

Which produces what I want except for the type constraint e.g.

namespace MyNS
{
    public static class TestExtensions
    {
        public static T SetTest<T>(this T definition, int value)
            where T :
        {
            definition.SetField("test", value);
            return definition;
        }
    }
}

GetSL().ToFullString() produces an empty result.

I need the type constraint to be: where T : Test

I can't find any examples for WithConstraints() so far.


Solution

  • You almost got the correct result. The main issue in your GetSL method. Because SeparatedSyntaxList<TypeParameterConstraintSyntax> is immutable you have to use return value of Add method.

    That variant works:

    var parameterConstraintClauseSyntax = SyntaxFactory.TypeParameterConstraintClause(
      SyntaxFactory.IdentifierName("T"),
      new SeparatedSyntaxList<TypeParameterConstraintSyntax>()
       .Add(SyntaxFactory.TypeConstraint(SyntaxFactory.ParseTypeName("Test"))));
    
    methodSyntax = methodSyntax.AddConstraintClauses(parameterConstraintClauseSyntax);