internal static SourceCode Generate(SourceGenerationOptions options) { using var builder = new SourceBuilder() .WriteLine(GeneratedFilesHeader) .WriteLine("using System;") .WriteLine() .WriteLine($"namespace {RootNamespace}") .WriteOpeningBracket(); if (options.GenerateXmlDocument) { builder .WriteLine("/// <summary>") .WriteLine("/// Specifies that the annotated class can be mapped from the provided <see cref=\"SourceType\"/>.") .WriteLine("/// </summary>"); } builder .WriteLine("[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]") .WriteLine($"public sealed class {AttributeName}Attribute : Attribute") .WriteOpeningBracket(); if (options.GenerateXmlDocument) { builder .WriteLine("/// <summary>") .WriteLine($"/// Initializes a new instance of the <see cref=\"{AttributeName}Attribute\"/> class with the specified <paramref name=\"sourceType\"/>.") .WriteLine("/// </summary>") .WriteLine("/// <param name=\"sourceType\">The type of to map from.</param>"); } builder .WriteLine($"public {AttributeName}Attribute(Type sourceType)") .WriteOpeningBracket() .WriteLine("SourceType = sourceType;") .WriteClosingBracket() .WriteLine(); if (options.GenerateXmlDocument) { builder .WriteLine("/// <summary>") .WriteLine("/// Gets the type to map from.") .WriteLine("/// </summary>"); } builder .WriteLine("public Type SourceType { get; }") .WriteClosingBracket() // class .WriteClosingBracket(); // namespace return(new(builder.ToString(), $"{AttributeName}Attribute.g.cs")); }
internal static SourceCode Generate(SourceGenerationOptions options) { using var builder = new SourceBuilder() .WriteLine(GeneratedFilesHeader) .WriteNullableContextOptionIf(options.SupportNullableReferenceTypes) .WriteLine() .WriteLine("using System;") .WriteLine() .WriteLine($"namespace {RootNamespace}") .WriteOpeningBracket(); if (options.GenerateXmlDocument) { builder .WriteLine("/// <summary>") .WriteLine("/// Specifies the mapping behavior of the annotated property.") .WriteLine("/// </summary>") .WriteLine("/// <remarks>") .WriteLine($"/// {AttributeClassName} has a number of uses:") .WriteLine("/// <list type=\"bullet\">") .WriteLine("/// <item><description>By default properties with same name will get mapped. This attribute allows the names to be different.</description></item>") .WriteLine("/// <item><description>Indicates that a property should be mapped when member serialization is set to opt-in.</description></item>") .WriteLine("/// </list>") .WriteLine("/// </remarks>"); } builder .WriteLine("[AttributeUsage(AttributeTargets.Property | AttributeTargets.Parameter, AllowMultiple = true)]") .WriteLine($"public sealed class {AttributeClassName} : Attribute") .WriteOpeningBracket(); if (options.GenerateXmlDocument) { builder .WriteLine("/// <summary>") .WriteLine("/// Gets or sets the property name of the object to mapping from.") .WriteLine("/// </summary>"); } builder .WriteLine($"public string{options.NullableReferenceSyntax} {SourcePropertyNamePropertyName} {{ get; set; }}") .WriteClosingBracket() // class .WriteClosingBracket(); // namespace return(new(builder.ToString(), $"{AttributeClassName}.g.cs")); }
internal static SourceCode Generate(SourceGenerationOptions options) { using var builder = new SourceBuilder() .WriteLine(GeneratedFilesHeader) .WriteNullableContextOptionIf(options.SupportNullableReferenceTypes) .WriteLine() .WriteLine($"namespace {RootNamespace}") .WriteOpeningBracket(); if (options.GenerateXmlDocument) { builder .WriteLine("/// <summary>") .WriteLine("/// Converts the value of <typeparamref name=\"TSource\"/> to <typeparamref name=\"TDestination\"/>.") .WriteLine("/// </summary>") .WriteLine("/// <typeparam name=\"TSource\">The type to convert from.</typeparam>") .WriteLine("/// <typeparam name=\"TDestination\">The type to convert to.</typeparam>"); } builder .WriteLine($"public interface {InterfaceName}<in TSource, out TDestination>") .WriteOpeningBracket(); if (options.GenerateXmlDocument) { builder .WriteLine("/// <summary>") .WriteLine("/// Converts the value of <paramref name=\"source\"/> object to <typeparamref name=\"TDestination\"/>.") .WriteLine("/// </summary>") .WriteLine("/// <param name=\"source\">The <see cref=\"TSource\"/> to convert.</param>") .WriteLine($"/// <param name=\"converterParameters\">The parameter list passed to the <see cref=\"{MapTypeConverterAttributeSource.AttributeClassName}\"/></param>") .WriteLine("/// <returns><typeparamref name=\"TDestination\"/> object.</returns>"); } builder .WriteLine($"TDestination Convert(TSource source, object[]{options.NullableReferenceSyntax} converterParameters);") .WriteClosingBracket() .WriteClosingBracket(); return(new(builder.ToString(), $"{InterfaceName}.g.cs")); }
internal static SourceCode Generate(MappingModel model) { using var builder = new SourceBuilder() .WriteLine(GeneratedFilesHeader) .WriteNullableContextOptionIf(model.Options.SupportNullableReferenceTypes) .WriteUsings(model.Usings) .WriteLine() // Namespace declaration .WriteLine($"namespace {model.Namespace}") .WriteOpeningBracket() // Class declaration .WriteLine($"partial record {model.TypeIdentifierName}") .WriteOpeningBracket(); // Class body if (model.GenerateSecondaryConstructor) { builder .GenerateSecondaryConstructor(model) .WriteLine(); } builder .GeneratePrivateConstructor(model) .WriteLine() .GenerateFactoryMethod(model) // End class declaration .WriteClosingBracket() .WriteLine() // Extension class declaration .GenerateSourceTypeExtensionClass(model) // End namespace declaration .WriteClosingBracket(); return(new(builder.ToString(), $"{model.Namespace}.{model.TypeIdentifierName}.g.cs")); }
internal static SourceCode Generate(SourceGenerationOptions options) { var builder = new SourceBuilder() .WriteLine(GeneratedFilesHeader) .WriteLine("using System;") .WriteLine() .WriteLine($"namespace {RootNamespace}") .WriteOpeningBracket(); if (options.GenerateXmlDocument) { builder .WriteLine("/// <summary>") .WriteLine("/// Specifies that the annotated property should be excluded.") .WriteLine("/// </summary>"); } builder .WriteLine("[AttributeUsage(AttributeTargets.Property, Inherited = false, AllowMultiple = false)]") .WriteLine($"public sealed class {AttributeClassName} : Attribute {{ }}") .WriteClosingBracket(); return(new(builder.ToString(), $"{AttributeClassName}.g.cs")); }
internal static SourceCode Generate(SourceGenerationOptions options) { var usings = new List <string> { "System", "System.Collections.Generic", "System.Reflection" }; using var builder = new SourceBuilder() .WriteLine(GeneratedFilesHeader) .WriteLine() .WriteUsings(usings) .WriteLine() // Namespace declaration .WriteLine($"namespace {RootNamespace}") .WriteOpeningBracket() // Class declaration .WriteLine($"internal sealed class {ClassName}") .WriteOpeningBracket() .WriteLine("private readonly Dictionary<object, object> _cache;") .WriteLine() // Constructor .WriteLine($"internal {ClassName}()") .WriteOpeningBracket() .WriteLine("_cache = new Dictionary<object, object>(1);") .WriteClosingBracket() .WriteLine() // Factory .WriteLine($"internal static TMapped {FactoryMethodName}<TOriginal, TMapped>(TOriginal original)") .WriteOpeningBracket() .WriteLine("if (original == null) throw new ArgumentNullException(nameof(original));") .WriteLine() .WriteLine("var context = new MappingContext();") .WriteLine("var mapped = context.MapFromWithContext<TOriginal, TMapped>(original);") .WriteLine() .WriteLine("if (mapped == null)") .WriteOpeningBracket() .WriteLine("throw new InvalidOperationException();") .WriteClosingBracket() .WriteLine() .WriteLine("return mapped;") .WriteClosingBracket() .WriteLine() // MapFromWithContext method .WriteLine($"internal TMapped MapFromWithContext<TOriginal, TMapped>(TOriginal original)") .WriteOpeningBracket() .WriteLine("if (original == null)") .WriteOpeningBracket() .WriteLine("return default(TMapped);") .WriteClosingBracket() .WriteLine() .WriteLine("if (!TryGetValue<TOriginal, TMapped>(original, out var mapped))") .WriteOpeningBracket() .WriteLine("var instance = Activator.CreateInstance(typeof(TMapped), BindingFlags.Instance | BindingFlags.NonPublic, null, new object[] { this, original }, null);") .WriteLine("if (instance != null)") .WriteOpeningBracket() .WriteLine("mapped = (TMapped)instance;") .WriteClosingBracket() .WriteClosingBracket() .WriteLine() .WriteLine("return mapped;") .WriteClosingBracket() .WriteLine() // Register method .WriteLine("internal void Register<TOriginal, TMapped>(TOriginal original, TMapped mapped)") .WriteOpeningBracket() .WriteLine("if (original == null) throw new ArgumentNullException(nameof(original));") .WriteLine("if (mapped == null) throw new ArgumentNullException(nameof(mapped));") .WriteLine() .WriteLine("if (!_cache.ContainsKey(original))") .WriteOpeningBracket() .WriteLine("_cache.Add(original, mapped);") .WriteClosingBracket() .WriteClosingBracket() .WriteLine() // TryGetValue method .WriteLine("private bool TryGetValue<TOriginal, TMapped>(TOriginal original, out TMapped mapped)") .WriteOpeningBracket() .WriteLine("if (original != null && _cache.TryGetValue(original, out var value))") .WriteOpeningBracket() .WriteLine("mapped = (TMapped)value;") .WriteLine("return true;") .WriteClosingBracket() .WriteLine() .WriteLine("mapped = default(TMapped);") .WriteLine("return false;") .WriteClosingBracket() // End class declaration .WriteClosingBracket() // End namespace declaration .WriteClosingBracket(); return(new(builder.ToString(), $"{ClassName}.g.cs")); }
internal static SourceCode Generate(SourceGenerationOptions options) { using var builder = new SourceBuilder() .WriteLine(GeneratedFilesHeader) .WriteNullableContextOptionIf(options.SupportNullableReferenceTypes) .WriteLine() .WriteLine("using System;") .WriteLine() .WriteLine($"namespace {RootNamespace}") .WriteOpeningBracket(); if (options.GenerateXmlDocument) { builder .WriteLine("/// <summary>") .WriteLine("/// Specifies what type to use as a converter for the property this attribute is bound to.") .WriteLine("/// </summary>"); } builder .WriteLine("[AttributeUsage(AttributeTargets.Property | AttributeTargets.Parameter, AllowMultiple = false)]") .WriteLine($"public sealed class {AttributeClassName} : Attribute") .WriteOpeningBracket(); if (options.GenerateXmlDocument) { builder .WriteLine("/// <summary>") .WriteLine($"/// Initializes a new instance of <see cref=\"{AttributeClassName}\"/>.") .WriteLine("/// </summary>") .WriteLine($"/// <param name=\"converter\">The <see cref=\"{ITypeConverterSource.InterfaceName}{{TSource,TDestination}}\" /> to be used to convert the source type.</param>") .WriteLine("/// <param name=\"converterParameters\">The list of parameters to pass to the <paramref name=\"converter\"/> during the type conversion.</param>"); } builder .WriteLine($"public {AttributeClassName}(Type converter, object[]{options.NullableReferenceSyntax} converterParameters = null)") .WriteOpeningBracket() .WriteLine($"{ConverterPropertyName} = converter;") .WriteLine($"{ConverterParametersPropertyName} = converterParameters;") .WriteClosingBracket() .WriteLine(); if (options.GenerateXmlDocument) { builder .WriteLine("/// <summary>") .WriteLine($"/// Gets or sets the <see cref=\"{ITypeConverterSource.InterfaceName}{{TSource,TDestination}}\" /> to be used to convert the source type.") .WriteLine("/// </summary>"); } builder .WriteLine($"public Type {ConverterPropertyName} {{ get; }}") .WriteLine(); if (options.GenerateXmlDocument) { builder .WriteLine("/// <summary>") .WriteLine($"/// Gets the list of parameters to pass to the <see cref=\"{ConverterPropertyName}\"/> during the type conversion.") .WriteLine("/// </summary>"); } builder .WriteLine($"public object[]{options.NullableReferenceSyntax} {ConverterParametersPropertyName} {{ get; }}") .WriteClosingBracket() .WriteClosingBracket(); return(new(builder.ToString(), $"{AttributeClassName}.g.cs")); }