updates
This commit is contained in:
parent
69c2733046
commit
95fc3e43d7
|
|
@ -9,6 +9,7 @@ using System.Diagnostics;
|
|||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Metadata.Ecma335;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
|
|
@ -80,15 +81,17 @@ namespace AutoMapProperty
|
|||
public List<string> Usings;
|
||||
public string Namespace;
|
||||
public string Name;
|
||||
public string FullName => Namespace + "." + Name;
|
||||
|
||||
public record struct ProperyGenerationInfo(PropertyDeclarationSyntax prop, bool customFrom, IMethodSymbol? customFromMethod, bool customTo, IMethodSymbol? customToMethod);
|
||||
public record struct ProperyGenerationInfo(PropertyDeclarationSyntax prop, ITypeSymbol propTypeSymbol, bool customFrom, IMethodSymbol? customFromMethod, bool customTo, IMethodSymbol? customToMethod);
|
||||
public List<ProperyGenerationInfo> Properties;
|
||||
|
||||
public struct MappableTypes
|
||||
{
|
||||
public string From;
|
||||
public string To;
|
||||
public ITypeSymbol FromType;
|
||||
public ITypeSymbol ToType;
|
||||
|
||||
public ClassToGenerate OurTargetType;
|
||||
public IPropertySymbol FromProperty;
|
||||
public bool FromIsReadOnly => FromProperty.SetMethod == null;
|
||||
|
||||
|
|
@ -96,15 +99,16 @@ namespace AutoMapProperty
|
|||
public IMethodSymbol? CustomFromMethod;
|
||||
public bool CustomTo;
|
||||
public IMethodSymbol? CustomToMethod;
|
||||
public MappableTypes(string from, string to, IPropertySymbol fromProperty, bool customFrom, IMethodSymbol? customFromMethod, bool customTo, IMethodSymbol? customToMethod, bool generateConverter = true)
|
||||
public MappableTypes(ITypeSymbol from, ITypeSymbol to, IPropertySymbol fromProperty, bool customFrom, IMethodSymbol? customFromMethod, bool customTo, IMethodSymbol? customToMethod, ClassToGenerate? isOurType)
|
||||
{
|
||||
From = from;
|
||||
To = to;
|
||||
FromType = from;
|
||||
ToType = to;
|
||||
FromProperty = fromProperty;
|
||||
CustomFrom = customFrom;
|
||||
CustomFromMethod = customFromMethod;
|
||||
CustomTo = customTo;
|
||||
CustomToMethod = customToMethod;
|
||||
OurTargetType = isOurType;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -205,7 +209,7 @@ namespace AutoMapProperty
|
|||
classesToGenerate[name] = new ClassToGenerate(PropParentDecl, name, ns, usings, new List<ClassToGenerate.ProperyGenerationInfo>());
|
||||
}
|
||||
|
||||
var mem = propSyntax;
|
||||
PropertyDeclarationSyntax? mem = propSyntax;
|
||||
try
|
||||
{
|
||||
var newList = GetModifiedAttributeList(compilation, propSyntax.AttributeLists);
|
||||
|
|
@ -232,11 +236,14 @@ namespace AutoMapProperty
|
|||
);
|
||||
}
|
||||
|
||||
var typeSymbol = propSymbol.Type;
|
||||
|
||||
//If we have a special overwrite type, replace it
|
||||
if (attr.ConstructorArguments.Count() >= 2)
|
||||
{
|
||||
INamedTypeSymbol dataTypename = attr?.ConstructorArguments[1].Value as INamedTypeSymbol;
|
||||
mem = mem.WithType(SyntaxFactory.ParseTypeName(dataTypename.ToDisplayString() + " "));
|
||||
typeSymbol = dataTypename;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -258,6 +265,12 @@ namespace AutoMapProperty
|
|||
mem = mem.WithInitializer(null);
|
||||
mem = mem.WithExpressionBody(null);
|
||||
|
||||
//if property is abstract remove the abstract modifier
|
||||
if (mem.Modifiers.Any(x => x.IsKind(SyntaxKind.AbstractKeyword)))
|
||||
{
|
||||
mem = mem.WithModifiers(SyntaxFactory.TokenList(mem.Modifiers.Where(x => !x.IsKind(SyntaxKind.AbstractKeyword))));
|
||||
}
|
||||
|
||||
//now the has trailing semicolon, which is wrong
|
||||
mem = mem.WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.None));
|
||||
|
||||
|
|
@ -278,7 +291,7 @@ namespace AutoMapProperty
|
|||
}
|
||||
//Add the property to the carrier type
|
||||
classesToGenerate[name].Properties.Add(
|
||||
new ClassToGenerate.ProperyGenerationInfo(mem, customFrom, customFromMethod, customTo, customToMethod)
|
||||
new ClassToGenerate.ProperyGenerationInfo(mem, typeSymbol, customFrom, customFromMethod, customTo, customToMethod)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -318,24 +331,23 @@ namespace AutoMapProperty
|
|||
return method;
|
||||
}
|
||||
|
||||
public record struct PropertyGenInfo(string type, IPropertySymbol? symbol = null, bool customFrom = false, IMethodSymbol? customFromMethod = null, bool customTo = false, IMethodSymbol? customToMethod = null);
|
||||
public record struct PropertyGenInfo(ITypeSymbol type, IPropertySymbol? symbol = null, bool customFrom = false, IMethodSymbol? customFromMethod = null, bool customTo = false, IMethodSymbol? customToMethod = null);
|
||||
|
||||
public static void ProcessClassToGenerateVariations(SourceProductionContext context, Compilation compilation, Dictionary<string, ClassToGenerate> classesToGenerate, ClassToGenerate cls)
|
||||
{
|
||||
var possibleCandidates = new List<(string, PropertyGenInfo)>();
|
||||
string newName = cls.Namespace + "." + cls.Name;
|
||||
//check if the newName already exists in compilation
|
||||
|
||||
var sym = compilation.GetTypesByMetadataName(newName).FirstOrDefault();
|
||||
var sym = compilation.GetTypesByMetadataName(cls.FullName).FirstOrDefault();
|
||||
|
||||
if (compilation.GetTypesByMetadataName(newName).FirstOrDefault() is INamedTypeSymbol symb)
|
||||
if (compilation.GetTypesByMetadataName(cls.FullName).FirstOrDefault() is INamedTypeSymbol symb)
|
||||
{
|
||||
possibleCandidates.AddRange(GetSymbolsForTypedSymbol(compilation, symb, classesToGenerate)
|
||||
.Select(x => (x.Item1, x.Item2)));
|
||||
}
|
||||
else
|
||||
{
|
||||
possibleCandidates.AddRange(GetInfoFromClassToGenerate(cls));
|
||||
possibleCandidates.AddRange(GetInfoFromClassToGenerate(compilation, cls));
|
||||
}
|
||||
|
||||
//get properties on the source class
|
||||
|
|
@ -360,7 +372,35 @@ namespace AutoMapProperty
|
|||
var sourceNames = source.ToDictionary(x => x.Item1, x => x.Item2);
|
||||
var possibleNames = possible.ToDictionary(x => x.Item1, x => x.Item2);
|
||||
cls.MappableProperties = possibleNames.Keys.Where(x => sourceNames.Keys.Contains(x))
|
||||
.ToDictionary(x => x, x => new ClassToGenerate.MappableTypes(sourceNames[x].type, possibleNames[x].type, sourceNames[x].symbol, possibleNames[x].customFrom, possibleNames[x].customFromMethod, possibleNames[x].customTo, possibleNames[x].customToMethod));
|
||||
.ToDictionary(x => x, x =>
|
||||
{
|
||||
var concreteType = GetConcreteType(possibleNames[x].type);
|
||||
var fullName = GetFullString(concreteType);
|
||||
var ourType = classesToGenerate.FirstOrDefault(y => y.Value.FullName == fullName).Value;
|
||||
|
||||
//could not be resolved due to missing namespace, lets be optimistic
|
||||
if (ourType == null && string.IsNullOrEmpty(concreteType.ContainingNamespace?.Name))
|
||||
{
|
||||
ourType = classesToGenerate.FirstOrDefault(y => y.Value.Name == fullName).Value;
|
||||
}
|
||||
/*
|
||||
if (!isOurType && !fullName.StartsWith("System"))
|
||||
{
|
||||
Console.WriteLine(x + "'s type: " + fullName + " is not in our types");
|
||||
Console.WriteLine(concreteType.ContainingNamespace.Name);
|
||||
Console.WriteLine(concreteType.Name);
|
||||
}*/
|
||||
|
||||
return new ClassToGenerate.MappableTypes(
|
||||
sourceNames[x].type,
|
||||
possibleNames[x].type,
|
||||
sourceNames[x].symbol,
|
||||
possibleNames[x].customFrom,
|
||||
possibleNames[x].customFromMethod,
|
||||
possibleNames[x].customTo,
|
||||
possibleNames[x].customToMethod,
|
||||
ourType);
|
||||
});
|
||||
//c.MappableProperties = c.MappableProperties.ToDictionary(x => x.Item1, x => x.Item2).Select(x => (x.Key, x.Value)).ToList();
|
||||
context.ReportDiagnostic(
|
||||
Diagnostic.Create(
|
||||
|
|
@ -370,10 +410,39 @@ namespace AutoMapProperty
|
|||
|
||||
}
|
||||
|
||||
static ITypeSymbol GetConcreteType(ITypeSymbol symb)
|
||||
{
|
||||
//if it's array, dicionary, etc. then we weant to check the underlying type
|
||||
if (symb is IArrayTypeSymbol arr)
|
||||
{
|
||||
//Console.WriteLine(symb.GetFullMetadataName() + " is array: " + GetFullString(arr.ElementType));
|
||||
return GetConcreteType(arr.ElementType);
|
||||
}
|
||||
//also check for ICollection and IEnumerable
|
||||
if (symb.Name == "ICollection" || symb.Name == "IEnumerable")
|
||||
{
|
||||
//if it's generic, then we want to check the underlying type
|
||||
if (symb is INamedTypeSymbol gen)
|
||||
{
|
||||
//Console.WriteLine(symb.GetFullMetadataName() + " is generic: " + GetFullString(gen.TypeArguments[0]));
|
||||
return GetConcreteType(gen.TypeArguments[0]);
|
||||
}
|
||||
}
|
||||
|
||||
return symb;
|
||||
}
|
||||
|
||||
static SymbolDisplayFormat displayFormat = new SymbolDisplayFormat(
|
||||
typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces,
|
||||
genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters,
|
||||
miscellaneousOptions: SymbolDisplayMiscellaneousOptions.IncludeNullableReferenceTypeModifier);
|
||||
|
||||
|
||||
public static List<(string, PropertyGenInfo)> GetSymbolsForTypedSymbol(Compilation comp, INamedTypeSymbol cls, Dictionary<string, ClassToGenerate> ctg)
|
||||
{
|
||||
var result = new List<(string, PropertyGenInfo)>();
|
||||
result.AddRange(cls.GetMembers().OfType<IPropertySymbol>().Select(x => (x.Name.Trim(), new PropertyGenInfo(x.Type.ToDisplayString().Trim(), x))));
|
||||
|
||||
result.AddRange(cls.GetMembers().OfType<IPropertySymbol>().Select(x => (x.Name.Trim(), new PropertyGenInfo(x.Type, x))));
|
||||
//add from to be generated symbols
|
||||
result.AddRange(GetSymbolsFromCurrentGeneration(comp, cls.Name.Trim(), ctg));
|
||||
|
||||
|
|
@ -388,14 +457,18 @@ namespace AutoMapProperty
|
|||
{
|
||||
var c = currentClassesToBeGenerated[className];
|
||||
|
||||
return GetInfoFromClassToGenerate(c);
|
||||
return GetInfoFromClassToGenerate(comp, c);
|
||||
}
|
||||
return new List<(string, PropertyGenInfo)>();
|
||||
}
|
||||
public static List<(string, PropertyGenInfo)> GetInfoFromClassToGenerate(ClassToGenerate cls)
|
||||
public static List<(string, PropertyGenInfo)> GetInfoFromClassToGenerate(Compilation comp, ClassToGenerate cls)
|
||||
{
|
||||
return cls.Properties.Select(x => (x.prop.Identifier.ToFullString().Trim(),
|
||||
new PropertyGenInfo(x.prop.Type.ToFullString().Trim(), (IPropertySymbol?)null, x.customFrom, x.customFromMethod, x.customTo, x.customToMethod)))
|
||||
return cls.Properties.Select(x =>
|
||||
{
|
||||
var name = x.prop.Identifier.ToFullString().Trim();
|
||||
return (name,
|
||||
new PropertyGenInfo(x.propTypeSymbol, (IPropertySymbol?)null, x.customFrom, x.customFromMethod, x.customTo, x.customToMethod));
|
||||
})
|
||||
.ToList();
|
||||
}
|
||||
|
||||
|
|
@ -448,50 +521,59 @@ namespace AutoMapProperty
|
|||
sb.Append(method.ContainingType.ToDisplayString()).Append(".").Append(method.Name);
|
||||
return sb.ToString();
|
||||
}
|
||||
public static string GeneratePropertyFrom(string Key, string Type, bool nullable = true)
|
||||
public static string GeneratePropertyFrom(string Key, ITypeSymbol FromType, ITypeSymbol ToType, bool nullable = true)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
sb.Append(Key).Append(@" = ");
|
||||
|
||||
//using regex check if the type is IEnumerable or IList or List or ICollection or HashSet or ISet(it can have leading namespace), if so remove them to get the original type
|
||||
//example System.Collections.Generic.IEnumerable<TestType>
|
||||
//example System.Collections.Generic.IList<TestType>
|
||||
//also catch the IEnumerable or IList or List or ICollection or HashSet or ISet and add the appropriate ToHashSet or ToSet or ToCollection or ToList
|
||||
var regex = new Regex(@"(?<type>(System\.Collections\.Generic\.)?(IEnumerable|IList|List|ICollection|HashSet|ISet)<(?<type2>.*)>)");
|
||||
var match = regex.Match(Type);
|
||||
if (match.Success)
|
||||
var concreteToType = GetConcreteType(ToType);
|
||||
var concreteFromType = GetConcreteType(FromType);
|
||||
|
||||
bool isArray = !SymbolEqualityComparer.Default.Equals(concreteToType, ToType);
|
||||
|
||||
if (isArray)
|
||||
{
|
||||
var type = match.Groups["type2"].Value;
|
||||
sb.Append("(").Append(Type).Append(@")(source.").Append(Key).Append(" != null ? ");
|
||||
sb.Append("(").Append(ToType).Append(@")(source.").Append(Key).Append(" != null ? ");
|
||||
sb.Append("source.").Append(Key);
|
||||
sb.Append(nullable ? "?" : "").Append(@".Select(x => (").Append(type).Append(@")x)").Append(nullable ? "?" : "");
|
||||
sb.Append(nullable ? "?" : "");
|
||||
if (!SymbolEqualityComparer.Default.Equals(concreteToType, concreteFromType))
|
||||
{
|
||||
sb.Append(@".Select(x => (").Append(GetFullString(concreteToType)).Append(@")x)");
|
||||
sb.Append(nullable ? "?" : "");
|
||||
}
|
||||
|
||||
//Add the appropriate ToHashSet or ToSet or ToCollection or ToList
|
||||
if (match.Groups["type"].Value.Contains("Set"))
|
||||
if (ToType.Name.Contains("Set"))
|
||||
sb.Append(@".ToHashSet()");
|
||||
else
|
||||
sb.Append(@".ToList()");
|
||||
|
||||
sb.Append(" : new ");
|
||||
if (match.Groups["type"].Value.Contains("Set"))
|
||||
sb.Append("HashSet<").Append(type).Append(">()");
|
||||
if (ToType.Name.Contains("Set"))
|
||||
sb.Append("HashSet<").Append(GetFullString(concreteToType)).Append(">()");
|
||||
else
|
||||
sb.Append("List<").Append(type).Append(">()");
|
||||
sb.Append("List<").Append(GetFullString(concreteToType)).Append(">()");
|
||||
|
||||
sb.Append(")");
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.Append("(").Append(Type).Append(@")source.").Append(Key);
|
||||
sb.Append("(").Append(ToType).Append(@")source.").Append(Key);
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public static string GetFullString(ITypeSymbol symbol)
|
||||
{
|
||||
return symbol.ToDisplayString(format: displayFormat);
|
||||
}
|
||||
|
||||
public static string? GenerateCorrectFromProperty(string Key, ClassToGenerate.MappableTypes Value, bool nullable = true)
|
||||
{
|
||||
if (!Value.CustomFrom)
|
||||
{
|
||||
return GeneratePropertyFrom(Key, Value.To, nullable);
|
||||
return GeneratePropertyFrom(Key, Value.FromType, Value.ToType, nullable);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -499,32 +581,85 @@ namespace AutoMapProperty
|
|||
return null;
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.Append(Key).Append(" = (").Append(Value.To).Append(@")").Append(GetFullMethodName(Value.CustomFromMethod)).Append(@"(providers, this, source.").Append(Key).Append(")");
|
||||
sb.Append(Key).Append(" = (").Append(GetFullString(Value.ToType)).Append(@")").Append(GetFullMethodName(Value.CustomFromMethod)).Append(@"(providers, this, source.").Append(Key).Append(")");
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
public static string GeneratePropertyTo(string Key, string Type)
|
||||
public static string GeneratePropertyTo(string Key, ITypeSymbol Type)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
sb.Append(Key).Append(@" = (").Append(Type).Append(@")this.").Append(Key);
|
||||
sb.Append(Key).Append(@" = (").Append(GetFullString(Type)).Append(@")this.").Append(Key);
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
public static string? GenerateCorrectToProperty(string Key, ClassToGenerate.MappableTypes Value)
|
||||
{
|
||||
var retSb = new StringBuilder();
|
||||
retSb.Append("source.");
|
||||
if (!Value.CustomTo)
|
||||
{
|
||||
return GeneratePropertyTo(Key, Value.From);
|
||||
if (Value.FromIsReadOnly)
|
||||
return null;
|
||||
retSb.Append(GeneratePropertyTo(Key, Value.FromType));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Value.CustomToMethod == null)
|
||||
return null;
|
||||
|
||||
//if it's readonly we are probably just mutating some other data based of of this one
|
||||
if (Value.FromIsReadOnly)
|
||||
{
|
||||
var callerSb = new StringBuilder();
|
||||
callerSb.Append(GetFullMethodName(Value.CustomToMethod)).Append(@"(providers, source, this.").Append(Key).Append(");");
|
||||
return callerSb.ToString();
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.Append(Key).Append(" = (").Append(Value.From).Append(@")").Append(GetFullMethodName(Value.CustomToMethod)).Append(@"(providers, source, this.").Append(Key).Append(")");
|
||||
return sb.ToString();
|
||||
sb.Append(Key).Append(" = (").Append(GetFullString(Value.FromType)).Append(@")").Append(GetFullMethodName(Value.CustomToMethod)).Append(@"(providers, source, this.").Append(Key).Append(")");
|
||||
retSb.Append(sb.ToString());
|
||||
}
|
||||
retSb.Append(";");
|
||||
return retSb.ToString();
|
||||
}
|
||||
public static string? GenerateEqualityOperator(string name, ClassToGenerate.MappableTypes Value, string? prefix = null)
|
||||
{
|
||||
var prefixedName = prefix == null ? name : prefix + "." + name;
|
||||
//if the type is also being generated we actually want to use the generated EqualityExpression
|
||||
if (Value.OurTargetType != null)
|
||||
{
|
||||
var concrecteType = GetConcreteType(Value.ToType);
|
||||
//cannot process collections/arrays
|
||||
if (SymbolEqualityComparer.Default.Equals(concrecteType, Value.ToType))
|
||||
{
|
||||
var childSb = new StringBuilder();
|
||||
|
||||
foreach (var prop in Value.OurTargetType.MappableProperties)
|
||||
{
|
||||
var op = GenerateEqualityOperator(prop.Key, prop.Value, prefixedName);
|
||||
if (string.IsNullOrEmpty(op))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
childSb.Append(@"
|
||||
").Append(op).Append(" && ");
|
||||
}
|
||||
childSb.Append(@"true");
|
||||
return childSb.ToString();
|
||||
}
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!SymbolEqualityComparer.Default.Equals(Value.FromType, Value.ToType))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var sb = new StringBuilder();
|
||||
sb.Append("item1.").Append(prefixedName).Append(" == item2.").Append(prefixedName);
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public static string GenerateExtensionClass(ClassToGenerate classToGenerate)
|
||||
|
|
@ -538,13 +673,29 @@ namespace AutoMapProperty
|
|||
|
||||
sb.Append(@"
|
||||
#nullable enable
|
||||
|
||||
#pragma warning disable CS8600
|
||||
#pragma warning disable CS8601
|
||||
#pragma warning disable CS8602
|
||||
#pragma warning disable CS8603
|
||||
#pragma warning disable CS8604
|
||||
#pragma warning disable CS8618
|
||||
#pragma warning disable CS8625
|
||||
|
||||
#pragma warning disable CS0109
|
||||
#pragma warning disable CS8767
|
||||
#pragma warning disable CS0659
|
||||
|
||||
namespace ").Append(classToGenerate.Namespace).Append(@"
|
||||
{
|
||||
[System.CodeDom.Compiler.GeneratedCode(""AutoMapProperty"", ""1.0.0"")]
|
||||
public partial ").Append(classToGenerate.SourceContainer is ClassDeclarationSyntax ? "class " : "interface ").Append(classToGenerate.Name);
|
||||
|
||||
if (classToGenerate.SourceContainer is ClassDeclarationSyntax && !classToGenerate.SourceContainer.Modifiers.Any(x => x.IsKind(SyntaxKind.AbstractKeyword)))
|
||||
{
|
||||
sb.Append(": IAutomappedAttribute<").Append(classToGenerate.SourceContainer.Identifier).Append(",").Append(classToGenerate.Name).Append(">");
|
||||
sb.Append(", System.Collections.Generic.IEqualityComparer<").Append(classToGenerate.Name).Append(">");
|
||||
}
|
||||
sb.Append(@"
|
||||
{");
|
||||
foreach (var prop in classToGenerate.Properties)
|
||||
|
|
@ -562,7 +713,7 @@ namespace ").Append(classToGenerate.Namespace).Append(@"
|
|||
return dat.ApplyFrom(null, source);
|
||||
}");
|
||||
sb.Append(@"
|
||||
public ").Append(classToGenerate.Name).Append(@" ApplyFrom(System.IServiceProvider providers, ").Append(classToGenerate.SourceContainer.Identifier).Append(@" source)
|
||||
public new ").Append(classToGenerate.Name).Append(@" ApplyFrom(System.IServiceProvider? providers, ").Append(classToGenerate.SourceContainer.Identifier).Append(@" source)
|
||||
{
|
||||
if(source == null)
|
||||
return null;
|
||||
|
|
@ -581,7 +732,7 @@ namespace ").Append(classToGenerate.Namespace).Append(@"
|
|||
return this;
|
||||
}");
|
||||
sb.Append(@"
|
||||
public System.Linq.Expressions.Expression<Func<").Append(classToGenerate.SourceContainer.Identifier).Append(", ").Append(classToGenerate.Name).Append(@">> GetProjectorFrom(System.IServiceProvider providers) => (source)=>new ").Append(classToGenerate.Name).Append(@"()
|
||||
public new System.Linq.Expressions.Expression<Func<").Append(classToGenerate.SourceContainer.Identifier).Append(", ").Append(classToGenerate.Name).Append(@">> GetProjectorFrom(System.IServiceProvider providers) => (source)=>new ").Append(classToGenerate.Name).Append(@"()
|
||||
{");
|
||||
foreach (var prop in classToGenerate.MappableProperties)
|
||||
{
|
||||
|
|
@ -596,53 +747,93 @@ namespace ").Append(classToGenerate.Namespace).Append(@"
|
|||
};");
|
||||
|
||||
sb.Append(@"
|
||||
public static System.Linq.Expressions.Expression<Func<").Append(classToGenerate.Name).Append(@", bool>> EqualExpression(System.IServiceProvider providers,").Append(classToGenerate.SourceContainer.Identifier).Append(@" item1) => (item2)=>
|
||||
public static new System.Linq.Expressions.Expression<Func<").Append(classToGenerate.Name).Append(@", bool>> EqualExpression(System.IServiceProvider providers,").Append(classToGenerate.SourceContainer.Identifier).Append(@" item1) => (item2)=>
|
||||
(");
|
||||
foreach (var prop in classToGenerate.MappableProperties)
|
||||
{
|
||||
if (prop.Value.From != prop.Value.To)
|
||||
var op = GenerateEqualityOperator(prop.Key, prop.Value);
|
||||
if (string.IsNullOrEmpty(op))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
sb.Append(@"
|
||||
item1.").Append(prop.Key).Append(" == item2.").Append(prop.Key).Append(" && ");
|
||||
").Append(op).Append(" && ");
|
||||
}
|
||||
sb.Append(@"true
|
||||
);");
|
||||
|
||||
sb.Append(@"
|
||||
public static System.Linq.Expressions.Expression<Func<").Append(classToGenerate.SourceContainer.Identifier).Append(@", bool>> EqualExpression(System.IServiceProvider providers,").Append(classToGenerate.Name).Append(@" item1) => (item2)=>
|
||||
public static new System.Linq.Expressions.Expression<Func<").Append(classToGenerate.SourceContainer.Identifier).Append(@", bool>> EqualExpression(System.IServiceProvider providers,").Append(classToGenerate.Name).Append(@" item1) => (item2)=>
|
||||
(");
|
||||
foreach (var prop in classToGenerate.MappableProperties)
|
||||
{
|
||||
if (prop.Value.From != prop.Value.To)
|
||||
var op = GenerateEqualityOperator(prop.Key, prop.Value);
|
||||
if (string.IsNullOrEmpty(op))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
sb.Append(@"
|
||||
item1.").Append(prop.Key).Append(" == item2.").Append(prop.Key).Append(" && ");
|
||||
").Append(op).Append(" && ");
|
||||
}
|
||||
sb.Append(@"true
|
||||
);");
|
||||
|
||||
sb.Append(@"
|
||||
public override bool Equals(object obj){
|
||||
public override bool Equals(object? obj){
|
||||
if(obj == null)
|
||||
return false;
|
||||
|
||||
if (ReferenceEquals(obj, this))
|
||||
return true;
|
||||
|
||||
if (obj.GetType() != this.GetType())
|
||||
return false;
|
||||
|
||||
").Append(classToGenerate.Name).Append(@" other = obj as ").Append(classToGenerate.Name).Append(@";
|
||||
").Append(classToGenerate.Name).Append(@" item2 = obj as ").Append(classToGenerate.Name).Append(@";
|
||||
var item1 = this;
|
||||
|
||||
return (");
|
||||
foreach (var prop in classToGenerate.MappableProperties)
|
||||
{
|
||||
var op = GenerateEqualityOperator(prop.Key, prop.Value);
|
||||
if (string.IsNullOrEmpty(op))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
sb.Append(@"
|
||||
this.").Append(prop.Key).Append(" == other.").Append(prop.Key).Append(" && ");
|
||||
").Append(op).Append(" && ");
|
||||
}
|
||||
sb.Append(@"true
|
||||
);
|
||||
}");
|
||||
sb.Append(@"
|
||||
public bool Equals(").Append(classToGenerate.Name).Append(" item1, ").Append(classToGenerate.Name).Append(@" item2){
|
||||
|
||||
if (item1 is null || item2 is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ReferenceEquals(item1, item2))
|
||||
return true;
|
||||
|
||||
return (");
|
||||
foreach (var prop in classToGenerate.MappableProperties)
|
||||
{
|
||||
var op = GenerateEqualityOperator(prop.Key, prop.Value);
|
||||
if (string.IsNullOrEmpty(op))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
sb.Append(@"
|
||||
").Append(op).Append(" && ");
|
||||
}
|
||||
sb.Append(@"true
|
||||
);
|
||||
}");
|
||||
|
||||
sb.Append(@"
|
||||
public int GetHashCode(").Append(classToGenerate.Name).Append(@" obj)
|
||||
{
|
||||
return obj.GetHashCode();
|
||||
}");
|
||||
|
||||
var abstr = cds.Modifiers.Any(x => x.IsKind(SyntaxKind.AbstractKeyword));
|
||||
if (!abstr)
|
||||
|
|
@ -650,20 +841,18 @@ namespace ").Append(classToGenerate.Namespace).Append(@"
|
|||
|
||||
sb.Append(@"
|
||||
|
||||
public ").Append(classToGenerate.SourceContainer.Identifier).Append(@" ApplyTo(System.IServiceProvider providers, ").Append(classToGenerate.SourceContainer.Identifier).Append(@" source)
|
||||
public new ").Append(classToGenerate.SourceContainer.Identifier).Append(@" ApplyTo(System.IServiceProvider? providers, ").Append(classToGenerate.SourceContainer.Identifier).Append(@" source)
|
||||
{
|
||||
if(source == null)
|
||||
return null;
|
||||
{");
|
||||
foreach (var prop in classToGenerate.MappableProperties)
|
||||
{
|
||||
if (prop.Value.FromIsReadOnly)
|
||||
continue;
|
||||
var property = GenerateCorrectToProperty(prop.Key, prop.Value);
|
||||
if (property == null)
|
||||
continue;
|
||||
sb.Append(@"
|
||||
source.").Append(property).Append(@";");
|
||||
").Append(property);
|
||||
}
|
||||
sb.Append(@"
|
||||
}
|
||||
|
|
@ -682,10 +871,62 @@ namespace ").Append(classToGenerate.Namespace).Append(@"
|
|||
sb.Append(@"
|
||||
}
|
||||
}
|
||||
#pragma warning restore CS8600
|
||||
#pragma warning restore CS8601
|
||||
#pragma warning restore CS8602
|
||||
#pragma warning restore CS8603
|
||||
#pragma warning restore CS8604
|
||||
#pragma warning restore CS8618
|
||||
#pragma warning restore CS8625
|
||||
|
||||
#pragma warning restore CS0109
|
||||
#pragma warning restore CS8767
|
||||
#pragma warning restore CS0659
|
||||
|
||||
#nullable disable
|
||||
");
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public static class Utils
|
||||
{
|
||||
public static string GetFullMetadataName(this ISymbol s)
|
||||
{
|
||||
if (s == null || IsRootNamespace(s))
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
var sb = new StringBuilder(s.MetadataName);
|
||||
var last = s;
|
||||
|
||||
s = s.ContainingSymbol;
|
||||
|
||||
while (!IsRootNamespace(s))
|
||||
{
|
||||
if (s is ITypeSymbol && last is ITypeSymbol)
|
||||
{
|
||||
sb.Insert(0, '+');
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.Insert(0, '.');
|
||||
}
|
||||
|
||||
sb.Insert(0, s.OriginalDefinition.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat));
|
||||
//sb.Insert(0, s.MetadataName);
|
||||
s = s.ContainingSymbol;
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
private static bool IsRootNamespace(ISymbol symbol)
|
||||
{
|
||||
INamespaceSymbol s = null;
|
||||
return ((s = symbol as INamespaceSymbol) != null) && s.IsGlobalNamespace;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ namespace AutoMapPropertyHelper
|
|||
{
|
||||
public interface IAutomappedAttribute<TSource, TSelf>
|
||||
{
|
||||
public TSource ApplyTo(IServiceProvider providers, TSource value);
|
||||
public TSelf ApplyFrom(IServiceProvider providers, TSource source);
|
||||
public TSource ApplyTo(IServiceProvider? providers, TSource value);
|
||||
public TSelf ApplyFrom(IServiceProvider? providers, TSource source);
|
||||
|
||||
public Expression<Func<TSource, TSelf>> GetProjectorFrom(IServiceProvider providers);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user