This commit is contained in:
honzapatCZ 2023-06-27 20:57:22 +02:00
parent 69c2733046
commit 95fc3e43d7
2 changed files with 304 additions and 63 deletions

View File

@ -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;
}
}
}

View File

@ -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);
}