mirror of
https://github.com/zoriya/EntityFrameworkCore.Projectables.git
synced 2026-05-27 04:23:09 +00:00
Merge pull request #83 from am-creations/fix-generic-constraints
Add support for notnull, struct, class and new() generic constraints
This commit is contained in:
@@ -137,26 +137,48 @@ namespace EntityFrameworkCore.Projectables.Generator
|
|||||||
descriptor.ClassTypeParameterList = descriptor.ClassTypeParameterList.AddParameters(
|
descriptor.ClassTypeParameterList = descriptor.ClassTypeParameterList.AddParameters(
|
||||||
SyntaxFactory.TypeParameter(additionalClassTypeParameter.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat))
|
SyntaxFactory.TypeParameter(additionalClassTypeParameter.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat))
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// See https://github.com/dotnet/roslyn/blob/d7e010bbe5b1d37837417fc5e79ecb2fd9b7b487/src/VisualStudio/CSharp/Impl/ObjectBrowser/DescriptionBuilder.cs#L340
|
||||||
if (!additionalClassTypeParameter.ConstraintTypes.IsDefaultOrEmpty)
|
if (!additionalClassTypeParameter.ConstraintTypes.IsDefaultOrEmpty)
|
||||||
{
|
{
|
||||||
descriptor.ClassConstraintClauses ??= SyntaxFactory.List<TypeParameterConstraintClauseSyntax>();
|
descriptor.ClassConstraintClauses ??= SyntaxFactory.List<TypeParameterConstraintClauseSyntax>();
|
||||||
|
|
||||||
|
var parameters = new List<TypeConstraintSyntax>();
|
||||||
|
|
||||||
|
if (additionalClassTypeParameter.HasReferenceTypeConstraint)
|
||||||
|
{
|
||||||
|
parameters.Add(MakeTypeConstraint("class"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (additionalClassTypeParameter.HasValueTypeConstraint)
|
||||||
|
{
|
||||||
|
parameters.Add(MakeTypeConstraint("struct"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (additionalClassTypeParameter.HasNotNullConstraint)
|
||||||
|
{
|
||||||
|
parameters.Add(MakeTypeConstraint("notnull"));
|
||||||
|
}
|
||||||
|
|
||||||
|
parameters.AddRange(additionalClassTypeParameter
|
||||||
|
.ConstraintTypes
|
||||||
|
.Select(c =>
|
||||||
|
MakeTypeConstraint(c.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (additionalClassTypeParameter.HasConstructorConstraint)
|
||||||
|
{
|
||||||
|
parameters.Add(MakeTypeConstraint("new()"));
|
||||||
|
}
|
||||||
|
|
||||||
descriptor.ClassConstraintClauses = descriptor.ClassConstraintClauses.Value.Add(
|
descriptor.ClassConstraintClauses = descriptor.ClassConstraintClauses.Value.Add(
|
||||||
SyntaxFactory.TypeParameterConstraintClause(
|
SyntaxFactory.TypeParameterConstraintClause(
|
||||||
SyntaxFactory.IdentifierName(additionalClassTypeParameter.Name),
|
SyntaxFactory.IdentifierName(additionalClassTypeParameter.Name),
|
||||||
SyntaxFactory.SeparatedList<TypeParameterConstraintSyntax>(
|
SyntaxFactory.SeparatedList<TypeParameterConstraintSyntax>(parameters)
|
||||||
additionalClassTypeParameter
|
|
||||||
.ConstraintTypes
|
|
||||||
.Select(c => SyntaxFactory.TypeConstraint(
|
|
||||||
SyntaxFactory.IdentifierName(c.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat))
|
|
||||||
))
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo: add additional type constraints
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -245,5 +267,7 @@ namespace EntityFrameworkCore.Projectables.Generator
|
|||||||
|
|
||||||
return descriptor;
|
return descriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static TypeConstraintSyntax MakeTypeConstraint(string constraint) => SyntaxFactory.TypeConstraint(SyntaxFactory.IdentifierName(constraint));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -111,4 +111,4 @@ namespace EntityFrameworkCore.Projectables.Services
|
|||||||
return base.VisitMember(node);
|
return base.VisitMember(node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+20
@@ -0,0 +1,20 @@
|
|||||||
|
// <auto-generated/>
|
||||||
|
#nullable disable
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using EntityFrameworkCore.Projectables;
|
||||||
|
using Foo;
|
||||||
|
|
||||||
|
namespace EntityFrameworkCore.Projectables.Generated
|
||||||
|
{
|
||||||
|
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
|
||||||
|
static class Foo_Entity_FullName<T, TEnum>
|
||||||
|
where T : global::Foo.TypedObject<TEnum> where TEnum : struct, global::System.Enum
|
||||||
|
{
|
||||||
|
static global::System.Linq.Expressions.Expression<global::System.Func<global::Foo.Entity<T, TEnum>, string>> Expression()
|
||||||
|
{
|
||||||
|
return (global::Foo.Entity<T, TEnum> @this) => $"{@this.FirstName} {@this.LastName} {@this.SomeSubobject.SomeProp}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+19
@@ -0,0 +1,19 @@
|
|||||||
|
// <auto-generated/>
|
||||||
|
#nullable disable
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using EntityFrameworkCore.Projectables;
|
||||||
|
using Foo;
|
||||||
|
|
||||||
|
namespace EntityFrameworkCore.Projectables.Generated
|
||||||
|
{
|
||||||
|
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
|
||||||
|
static class Foo_Entity_FullName<T>
|
||||||
|
{
|
||||||
|
static global::System.Linq.Expressions.Expression<global::System.Func<global::Foo.Entity<T>, string>> Expression()
|
||||||
|
{
|
||||||
|
return (global::Foo.Entity<T> @this) => $"{@this.FirstName} {@this.LastName} {@this.SomeSubobject}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -7,7 +7,7 @@ namespace EntityFrameworkCore.Projectables.Generated
|
|||||||
{
|
{
|
||||||
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
|
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
|
||||||
static class _EntityBase_GetId<TId>
|
static class _EntityBase_GetId<TId>
|
||||||
where TId : global::System.ICloneable
|
where TId : global::System.ICloneable, new()
|
||||||
{
|
{
|
||||||
static global::System.Linq.Expressions.Expression<global::System.Func<TId>> Expression()
|
static global::System.Linq.Expressions.Expression<global::System.Func<TId>> Expression()
|
||||||
{
|
{
|
||||||
|
|||||||
+66
@@ -921,6 +921,72 @@ namespace Foo {
|
|||||||
return Verifier.Verify(result.GeneratedTrees[0].ToString());
|
return Verifier.Verify(result.GeneratedTrees[0].ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public Task GenericClassesWithContraints_AreRewritten()
|
||||||
|
{
|
||||||
|
var compilation = CreateCompilation(@"
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using EntityFrameworkCore.Projectables;
|
||||||
|
|
||||||
|
namespace Foo {
|
||||||
|
public class TypedObject<TEnum> where TEnum : struct, System.Enum
|
||||||
|
{
|
||||||
|
public TEnum SomeProp { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract class Entity<T, TEnum>where T : TypedObject<TEnum> where TEnum : struct, System.Enum
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public string FirstName { get; set; }
|
||||||
|
public string LastName { get; set; }
|
||||||
|
public T SomeSubobject { get; set; }
|
||||||
|
|
||||||
|
[Projectable]
|
||||||
|
public string FullName => $""{FirstName} {LastName} {SomeSubobject.SomeProp}"";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
");
|
||||||
|
var result = RunGenerator(compilation);
|
||||||
|
|
||||||
|
Assert.Empty(result.Diagnostics);
|
||||||
|
Assert.Single(result.GeneratedTrees);
|
||||||
|
|
||||||
|
return Verifier.Verify(result.GeneratedTrees[0].ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public Task GenericClassesWithTypeContraints_AreRewritten()
|
||||||
|
{
|
||||||
|
var compilation = CreateCompilation(@"
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using EntityFrameworkCore.Projectables;
|
||||||
|
|
||||||
|
namespace Foo {
|
||||||
|
public abstract class Entity<T> where T : notnull
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public string FirstName { get; set; }
|
||||||
|
public string LastName { get; set; }
|
||||||
|
public T SomeSubobject { get; set; }
|
||||||
|
|
||||||
|
[Projectable]
|
||||||
|
public string FullName => $""{FirstName} {LastName} {SomeSubobject}"";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
");
|
||||||
|
|
||||||
|
var result = RunGenerator(compilation);
|
||||||
|
|
||||||
|
Assert.Empty(result.Diagnostics);
|
||||||
|
// Assert.Single(result.GeneratedTrees);
|
||||||
|
|
||||||
|
return Verifier.Verify(result.GeneratedTrees[0].ToString());
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public Task DeclarationTypeNamesAreGettingFullyQualified()
|
public Task DeclarationTypeNamesAreGettingFullyQualified()
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user