Example #1
0
        private static string GenerateParameterSource(
            INamedTypeSymbol @class,
            IMethodSymbol method,
            IParameterSymbol parameter)
        {
            var namespaces = string.Join("\n",
                                         AlwaysActiveNamespaces
                                         .Append(@class.ContainingNamespace.ToDisplayString())
                                         .Append(@parameter.Type.ContainingNamespace.ToDisplayString())
                                         .Distinct()
                                         .OrderBy(x => x)
                                         .Select(x => $"using {x};"));

            var reflectionTypes = string.Join(", ",
                                              method.Parameters
                                              .Select(x => $"typeof({x.ToDisplayString()})"));

            return
                ($@"{namespaces}

namespace Finite.Commands.AttributedModel.Internal.Commands
{{
    internal class CommandFactory__{@class.Name}__{method.Name}__{parameter.Name}
        : IParameter
    {{
        private static readonly ParameterInfo Parameter
            = typeof({@class.Name})
                .GetMethod(
                    name: ""{method.Name}"",
                    genericParameterCount: {method.Arity},
                    bindingAttr: {GetBindingFlags(method)},
                    binder: default,
                    callConvention: {GetCallConv(method)},
                    types: new[]
                    {{
                        {reflectionTypes}
                    }},
                    modifiers: null)!
                .GetParameters()[{parameter.Ordinal}]!;

        private IReadOnlyDictionary<object, object?>? _data;

        public string Name {{ get; }} = ""{parameter.Name}"";
        public Type Type {{ get; }} = typeof({parameter.Type.ToDisplayString()});

        public IReadOnlyDictionary<object, object?> Data
        {{
            get
            {{
                return _data ??= new Dictionary<object, object?>(
                    GetData());
            }}
        }}

        private static IEnumerable<KeyValuePair<object, object?>> GetData()
            => DataProvider.GetData(Parameter);
    }}
}}");
        }
        private static string GenerateDataProviderSource(
            IEnumerable <string> providers)
        {
            var namespaces = string.Join("\n",
                                         AlwaysActiveNamespaces
                                         .Distinct()
                                         .OrderBy(x => x)
                                         .Select(x => $"using {x};"));

            var providerFactoryTypes = string.Join(", ",
                                                   providers.Select(x => $"new {x}()"));

            return
                ($@"{namespaces}

namespace Finite.Commands.AttributedModel.Internal.Commands
{{
    internal static class DataProvider
    {{
        private static readonly IAdditionalDataProviderFactory[] Factories
            = new IAdditionalDataProviderFactory[]
            {{
                {providerFactoryTypes}
            }};

        public static IEnumerable<KeyValuePair<object, object?>> GetData(
            MethodInfo method)
        {{
            foreach (var factory in Factories)
                foreach (var provider in factory.GetDataProvider(method))
                    foreach (var kvp in provider.GetData())
                        yield return kvp;
        }}

        public static IEnumerable<KeyValuePair<object, object?>> GetData(
            ParameterInfo parameter)
        {{
            foreach (var factory in Factories)
                foreach (var provider in factory.GetDataProvider(parameter))
                    foreach (var kvp in provider.GetData())
                        yield return kvp;
        }}
    }}
}}");
        }
        private static string GenerateCommandSource(
            INamedTypeSymbol @class,
            IMethodSymbol method,
            INamedTypeSymbol groupAttributeSymbol,
            INamedTypeSymbol commandAttributeSymbol)
        {
            string?commandPath;
            {
                var segment = GetStringFromAttribute(method,
                                                     commandAttributeSymbol);

                commandPath = $"new CommandString(\"{segment}\")";

                var currentClass = @class;
                do
                {
                    segment = GetStringFromAttribute(currentClass,
                                                     groupAttributeSymbol);

                    commandPath
                        = "CommandPath.Combine(" +
                          $"new CommandString(\"{segment}\"), " +
                          $"{commandPath})";

                    currentClass = @class.ContainingType;
                }while (currentClass != null);
            }

            var parameterNamespaces
                = method.Parameters
                  .Select(x => x.Type.ContainingNamespace.ToDisplayString());

            var parameterTypes = string.Join(", ",
                                             method.Parameters
                                             .Select(
                                                 x => $"new CommandFactory__{@class.Name}__{method.Name}__{x.Name}()"));

            var parameterAccessors = string.Join(", ",
                                                 method.Parameters
                                                 .Select(
                                                     x => $"({x.Type.ToDisplayString()})(context.Parameters[\"{x.Name}\"]!)"));

            var namespaces = string.Join("\n",
                                         AlwaysActiveNamespaces
                                         .Concat(parameterNamespaces)
                                         .Append(@class.ContainingNamespace.ToDisplayString())
                                         .Distinct()
                                         .OrderBy(x => x)
                                         .Select(x => $"using {x};"));

            var reflectionTypes = string.Join(", ",
                                              method.Parameters
                                              .Select(x => $"typeof({x.ToDisplayString()})"));

            return
                ($@"{namespaces}

namespace Finite.Commands.AttributedModel.Internal.Commands
{{
    internal class CommandFactory__{@class.Name}__{method.Name}
        : ICommand
    {{
        private static readonly ObjectFactory CommandClassFactory
            = ActivatorUtilities.CreateFactory(
                typeof({@class.Name}),
                Array.Empty<Type>());

        private static readonly MethodInfo Method
            = typeof({@class.Name})
                .GetMethod(
                    name: ""{method.Name}"",
                    genericParameterCount: {method.Arity},
                    bindingAttr: {GetBindingFlags(method)},
                    binder: default,
                    callConvention: {GetCallConv(method)},
                    types: new[]
                    {{
                        {reflectionTypes}
                    }},
                    modifiers: null)!;

        private IReadOnlyDictionary<object, object?>? _data;

        public CommandString Name {{ get; }} = {commandPath};

        public IReadOnlyList<IParameter> Parameters {{ get; }}
            = new IParameter[]
            {{
                {parameterTypes}
            }};

        public IReadOnlyDictionary<object, object?> Data
        {{
            get
            {{
                return _data ??= new Dictionary<object, object?>(
                    GetData());
            }}
        }}

        public async ValueTask<ICommandResult> ExecuteAsync(
            CommandContext context, CancellationToken cancellationToken)
        {{
            var commandClass = ({@class.Name})CommandClassFactory(
                context.Services, Array.Empty<object?>());

            Module.SetCommandContext(commandClass, context);
            Module.SetCancellationToken(commandClass, cancellationToken);

            try
            {{
                return await commandClass.{method.Name}({parameterAccessors});
            }}
            finally
            {{
                if (commandClass is IDisposable disposable)
                    disposable.Dispose();
            }}
        }}

        private static IEnumerable<KeyValuePair<object, object?>> GetData()
            => DataProvider.GetData(Method);
    }}
}}");
        }