9.8.2018.0630
大石头 authored at 2018-06-30 11:15:32
5.88 KiB
X
using System;
using System.Linq;
using System.Reflection;
using System.Threading;

#if NET4
namespace System
{
    internal abstract class Lightup
    {
        private static readonly Type[] EmptyTypes = new Type[0];

        private readonly Type _type;

        protected Lightup(Type type)
        {
            _type = type;
        }

        protected bool TryGet<T>(ref Delegate storage, string propertyName, out T value)
        {
            return TryCall(ref storage, "get_" + propertyName, out value);
        }

        protected T Get<T>(ref Delegate storage, string propertyName)
        {
            return Call<T>(ref storage, "get_" + propertyName);
        }

        protected void Set<T>(ref Delegate storage, string propertyName, T value)
        {
            Call(ref storage, "set_" + propertyName, value);
        }

        protected void Set<TI, TV>(ref Delegate storage, TI instance, string propertyName, TV value)
        {
            Call(ref storage, instance, "set_" + propertyName, value);
        }

        protected bool TrySet<TI, TV>(ref Delegate storage, TI instance, string propertyName, TV value)
        {
            return TryCall(ref storage, instance, "set_" + propertyName, value);
        }

        protected bool TryCall<T>(ref Delegate storage, string methodName, out T returnValue)
        {
            Func<T> methodAccessor = GetMethodAccessor<Func<T>>(ref storage, methodName, true);
            if (methodAccessor == null)
            {
                returnValue = default(T);
                return false;
            }
            returnValue = methodAccessor.Invoke();
            return true;
        }

        protected T Call<T>(ref Delegate storage, string methodName)
        {
            Func<T> methodAccessor = GetMethodAccessor<Func<T>>(ref storage, methodName, true);
            if (methodAccessor == null)
            {
                throw new InvalidOperationException();
            }
            return methodAccessor.Invoke();
        }

        protected void Call(ref Delegate storage, string methodName)
        {
            Action methodAccessor = GetMethodAccessor<Action>(ref storage, methodName, true);
            if (methodAccessor == null)
            {
                throw new InvalidOperationException();
            }
            methodAccessor.Invoke();
        }

        protected bool TryCall<TI, TV>(ref Delegate storage, TI instance, string methodName, TV parameter)
        {
            Action<TI, TV> methodAccessor = GetMethodAccessor<Action<TI, TV>>(ref storage, methodName, false);
            if (methodAccessor == null)
            {
                return false;
            }
            methodAccessor.Invoke(instance, parameter);
            return true;
        }

        protected bool TryCall<TI, TV1, TV2>(ref Delegate storage, TI instance, string methodName, TV1 parameter1, TV2 parameter2)
        {
            Action<TI, TV1, TV2> methodAccessor = GetMethodAccessor<Action<TI, TV1, TV2>>(ref storage, methodName, false);
            if (methodAccessor == null)
            {
                return false;
            }
            methodAccessor.Invoke(instance, parameter1, parameter2);
            return true;
        }

        protected void Call<TI, TV>(ref Delegate storage, TI instance, string methodName, TV parameter)
        {
            Action<TI, TV> methodAccessor = GetMethodAccessor<Action<TI, TV>>(ref storage, methodName, false);
            if (methodAccessor == null)
            {
                throw new InvalidOperationException();
            }
            methodAccessor.Invoke(instance, parameter);
        }

        protected void Call<T>(ref Delegate storage, string methodName, T parameter)
        {
            Action<T> methodAccessor = GetMethodAccessor<Action<T>>(ref storage, methodName, true);
            if (methodAccessor == null)
            {
                throw new InvalidOperationException();
            }
            methodAccessor.Invoke(parameter);
        }

        protected static T Create<T>(params object[] parameters)
        {
            Type[] argumentTypes = Enumerable.ToArray(Enumerable.Select<object, Type>(parameters, (object p) => p.GetType()));
            Func<object[], T> func = CreateActivator<T>(argumentTypes);
            return func.Invoke(parameters);
        }

        protected abstract object GetInstance();

        private static Func<object[], T> CreateActivator<T>(Type[] argumentTypes)
        {
            if (typeof(T).GetConstructor(argumentTypes) == null) return null;

            return (object[] arguments) => (T)((object)Activator.CreateInstance(typeof(T), arguments));
        }

        private Delegate CreateMethodAccessor(Type type, string name, bool bindInstance = true)
        {
            if (_type == null) return null;

            Type[] methodArgumentTypes = LightupServices.GetMethodArgumentTypes(type, bindInstance);
            MethodInfo method = _type.GetMethod(name, methodArgumentTypes);
            if (method == null) return null;

            return LightupServices.CreateDelegate(type, bindInstance ? GetInstance() : null, method);
        }

        protected T GetMethodAccessor<T>(ref Delegate storage, string name, bool bindInstance = true)
        {
            return (T)((object)GetMethodAccessor(ref storage, typeof(T), name, bindInstance));
        }

        protected Delegate GetMethodAccessor(ref Delegate storage, Type type, string name, bool bindInstance = true)
        {
            if (storage == null)
            {
                var dlg = CreateMethodAccessor(type, name, bindInstance);
                Interlocked.CompareExchange(ref storage, dlg, null);
            }
            if (storage != LightupServices.NotFound) return storage;

            return null;
        }
    }
}
#endif