/// <summary>
        /// Generates the method signature with the specified variables.
        /// </summary>
        /// <typeparam name="T">The return type.</typeparam>
        /// <param name="variables">The variable names.</param>
        /// <returns>The generated method signature.</returns>
        private static string GenerateMethodSignature <T>(IDictionary <string, Type> variables)
        {
            // Convert types to presentation types if needed.
            var presentationVariables = new Dictionary <string, Type>();

            foreach (var variable in variables)
            {
                if (PresentationConverters.TryGetPresentationType(variable.Value, out Type? presentation))
                {
                    presentationVariables[variable.Key] = presentation;
                }
                else
                {
                    presentationVariables[variable.Key] = variable.Value;
                }
            }

            StringBuilder bldr = new StringBuilder();

            bldr.AppendLine("using LegendsGenerator.Contracts;");
            bldr.AppendLine("using LegendsGenerator.Contracts.Things;");
            bldr.AppendLine("using LegendsGenerator.Compiler.CSharp.Presentation;");
            bldr.Append($"{typeof(T).Name} EvaluateCondition(");
            bldr.AppendJoin(", ", presentationVariables.Select(v => $"{v.Value.Name} {v.Key}"));
            bldr.Append(") {");

            return(bldr.ToString());
        }
        /// <inheritdoc/>
        public TOut Evaluate(Random random, IDictionary <string, BaseThing> variables)
        {
            IList <object?> functionParameters = new List <object?>();
            var             globals            = this.globalVariables.ToDictionary();

            foreach (var variableName in this.variableNames)
            {
                if (variableName.Equals(Constants.RandomVariableName, StringComparison.OrdinalIgnoreCase))
                {
                    functionParameters.Add(random);
                }
                else if (globals.TryGetValue(variableName, out object?value))
                {
                    functionParameters.Add(value);
                }
                else if (variables.TryGetValue(variableName, out BaseThing? thing))
                {
                    // We need to convert things to their presentation type if needed.
                    if (PresentationConverters.TryConvertToPresentationType(thing, this.globalVariables.World ?? throw new InvalidOperationException("Global variable World can not be null."), out object?presentation))
                    {
                        functionParameters.Add(presentation);
                    }
                    else
                    {
                        functionParameters.Add(thing);
                    }
                }
                else
                {
                    functionParameters.Add(null);
                }
            }

            return(this.compiledCondition(functionParameters.ToArray()));
        }
        /// <inheritdoc/>
        public IList <BaseTypeMember> GetPublicMembers(Type type)
        {
            // Convert normal types to presentation types.
            if (PresentationConverters.TryGetPresentationType(type, out Type? presType))
            {
                type = presType;
            }

            List <BaseTypeMember> options = new List <BaseTypeMember>();

            foreach (var property in type.GetProperties().OrderBy(x => x.Name))
            {
                options.Add(new PropertyMember(property.Name, property.PropertyType));
            }

            foreach (System.Reflection.MethodInfo method in type.GetMethods().OrderBy(x => x.Name).ThenBy(x => x.GetParameters().Length).Where(m => !m.IsSpecialName && !this.ignoredMethods.Contains(m.Name)))
            {
                options.Add(new MethodMember(method.Name, method.ReturnType, method.GetParameters().Select(p => new MethodParameter(p.Name !, p.ParameterType)).ToList()));
            }

            return(options);
        }