Ejemplo n.º 1
0
        /*********
        ** Private methods
        *********/
        /// <summary>Try to get a method which matches the given delegate.</summary>
        /// <param name="instance">The token value provider.</param>
        /// <param name="name">The method name on <see cref="ConventionWrapper"/> being mapped.</param>
        /// <param name="methodDelegate">The created method delegate, if any.</param>
        /// <param name="error">The error indicating why creating the wrapper failed, if applicable.</param>
        private static bool TryWrapMethod <TDelegate>(object instance, string name, out TDelegate methodDelegate, out string error)
            where TDelegate : Delegate
        {
            methodDelegate = null;
            error          = null;

            // check target method exists
            {
                MethodInfo[] candidates = instance.GetType().GetMethods().Where(p => p.Name == name).ToArray();
                if (candidates.Length == 0)
                {
                    return(false);
                }
                if (candidates.Length > 1)
                {
                    return(Fail($"method {name} has multiple implementations.", out error));
                }
            }

            // map to delegate
            try
            {
                methodDelegate = (TDelegate)Delegate.CreateDelegate(typeof(TDelegate), instance, name);
                error          = null;
                return(true);
            }
            catch (ArgumentException ex)
            {
                methodDelegate = null;
                return(Fail(ConventionWrapper.GetMethodMismatchError(instance, name, ex), out error));
            }
        }
Ejemplo n.º 2
0
        /*********
        ** Public methods
        *********/
        /// <summary>Try to create a convention wrapper for a given token instance.</summary>
        /// <param name="instance">The token instance.</param>
        /// <param name="reflection">Simplifies access to private code.</param>
        /// <param name="wrapper">The wrapper, if created successfully.</param>
        /// <param name="error">The error indicating why creating the wrapper failed, if applicable.</param>
        public static bool TryCreate(object instance, IReflectionHelper reflection, [NotNullWhen(true)] out ConventionWrapper?wrapper, [NotNullWhen(false)] out string?error)
        {
            error = null;
            var result = new ConventionWrapper();

            // Map a delegate type to a token method and wrapper field by convention.
            // This assumes the delegate type name matches the method name, and the wrapper has a
            // field of the delegate type in the form {name}Impl.
            bool TryMap <TDelegate>([NotNullWhen(false)] out string?mapError) where TDelegate : Delegate
Ejemplo n.º 3
0
        /*********
        ** Public methods
        *********/
        /// <summary>Try to create a convention wrapper for a given token instance.</summary>
        /// <param name="instance">The token instance.</param>
        /// <param name="reflection">Simplifies access to private code.</param>
        /// <param name="wrapper">The wrapper, if created successfully.</param>
        /// <param name="error">The error indicating why creating the wrapper failed, if applicable.</param>
        public static bool TryCreate(object instance, IReflectionHelper reflection, out ConventionWrapper wrapper, out string error)
        {
            error = null;
            var result = new ConventionWrapper();

            // Map a delegate type to a token method and wrapper field by convention.
            // This assumes the delegate type name matches the method name, and the wrapper has a
            // field of the delegate type in the form {name}Impl.
            bool TryMap <TDelegate>(out string mapError) where TDelegate : Delegate
            {
                string methodName = typeof(TDelegate).Name;
                string fieldName  = $"{methodName}Impl";

                if (ConventionWrapper.TryWrapMethod(instance, methodName, out TDelegate mapped, out mapError))
                {
                    reflection.GetField <TDelegate>(result, fieldName).SetValue(mapped);
                }

                return(mapError == null);
            }

            // detect unknown methods
            bool succeeded = true;

            {
                string[] unknownMethods =
                    (
                        from MethodInfo method in instance.GetType().GetMethods()
                        where typeof(ConventionWrapper).GetMethod(method.Name) == null
                        select method.Name
                    )
                    .ToArray();
                if (unknownMethods.Any())
                {
                    succeeded = false;
                    error     = unknownMethods.Length == 1
                        ? $"found unsupported '{unknownMethods[0]}' method"
                        : $"found unsupported methods: {string.Join(", ", unknownMethods)}";
                }
            }

            // map implemented fields
            if (succeeded)
            {
                succeeded =
                    // metadata
                    TryMap <ConventionDelegates.IsMutable>(out error) &&
                    TryMap <ConventionDelegates.AllowsInput>(out error) &&
                    TryMap <ConventionDelegates.RequiresInput>(out error) &&
                    TryMap <ConventionDelegates.CanHaveMultipleValues>(out error) &&
                    TryMap <ConventionDelegates.GetValidInputs>(out error) &&
                    TryMap <ConventionDelegates.HasBoundedValues>(out error) &&
                    TryMap <ConventionDelegates.HasBoundedRangeValues>(out error) &&
                    TryMap <ConventionDelegates.TryValidateInput>(out error) &&
                    TryMap <ConventionDelegates.TryValidateValues>(out error) &&
                    TryMap <ConventionDelegates.NormalizeValue>(out error)

                    // state
                    && TryMap <ConventionDelegates.IsReady>(out error) &&
                    TryMap <ConventionDelegates.GetValues>(out error) &&
                    TryMap <ConventionDelegates.UpdateContext>(out error);
            }

            wrapper = succeeded ? result : null;
            return(succeeded);
        }
 /*********
 ** Public methods
 *********/
 /// <summary>Construct an instance.</summary>
 /// <param name="name">The token name. This only needs to be unique for your mod; Content Patcher will prefix it with your mod ID automatically, like <c>Pathoschild.ExampleMod/SomeTokenName</c>.</param>
 /// <param name="provider">The mod-provided value provider.</param>
 public ConventionValueProvider(string name, ConventionWrapper provider)
 {
     this.Name     = name;
     this.Provider = provider;
     this.IsReady  = provider.IsReady();
 }