Re[12]: Приоритет вызова перегруженных методов
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 09.06.16 07:13
Оценка:
Здравствуйте, Sinix, Вы писали:
S>Не вопрос, как сделаете корректное разруливание перегрузок по значениям аргументов в GetMethod() — так сразу и приходите.

Идея такая создаем класс для сравнения

namespace CoreClrDLL
{

   

    public class ИнформацияОТипе: IComparable<ИнформацияОТипе>
    {
        public Type Тип;
        bool IsByRef;
        bool IsValue;
        int УровеньИерархии;
        bool IsNullable;
        public ИнформацияОТипе(Type type)
        {
            var TI = type.GetTypeInfo();
            IsByRef = TI.IsByRef;

           

            if (IsByRef)
            {
                Тип = type.GetElementType();
                TI = Тип.GetTypeInfo();
                
            }
            else
                Тип = type;


            IsValue = TI.IsValueType;

            if (IsValue)
            {
                УровеньИерархии = 0;
                if (TI.IsGenericType && TI.GetGenericTypeDefinition() == typeof(Nullable<>))
                {
                    IsNullable = true;

                    Тип = TI.GenericTypeArguments[0];
                }

            }
            else
                УровеньИерархии = НайтиУровень(0, Тип);


        }

        static int НайтиУровень(int Уровень, Type type)
        {

            if (type == typeof(object))
                return Уровень;

            return НайтиУровень(Уровень + 1, type.GetTypeInfo().BaseType);

        }

       
        public  int CompareTo(ИнформацияОТипе elem)
        {
           

            int res = -IsByRef.CompareTo(elem.IsByRef);

            if (res != 0) return res;

            if (Тип == elem.Тип)
                return 0;

            res = -IsValue.CompareTo(elem.IsValue);

            if (res != 0) return res;


            if (IsValue && elem.IsValue)
            {
                res = IsNullable.CompareTo(elem.IsNullable);

                if (res != 0) return res;

            }

            res = -УровеньИерархии.CompareTo(elem.УровеньИерархии);

            if (res != 0) return res;

           

            return Тип.ToString().CompareTo(elem.Тип.ToString());
        }

        public bool Равняется(Type type)
        {

            if (type==null)
            {
                if (!IsValue)
                    return true;

                if (IsNullable)
                    return true;
                else
                    return false;

            }

            // или использовать IsInstanceOfType
            if (IsValue) return Тип == type;

                return Тип.IsAssignableFrom(type);

        }
    }


    

    public class ИнфoрмацияОМетоде<T>  where T : MethodBase
    {
        public T Method;
        public ИнформацияОТипе[] Параметры;
        public int КоличествоПараметров;
        public bool hasParams;
        public Type TypeParams;
        public int КоличествоПараметровПарамс;
        public ИнформацияОТипе ИнформацияОТипеЭлемента;

        public static Dictionary<Type, ИнформацияОТипе> ИнформацияПоТипу = new Dictionary<Type, ИнформацияОТипе>();

        public static ИнформацияОТипе ПолучитьИнформациюОТипе(Type type)
        {
            ИнформацияОТипе ИТ = null;
            if (!ИнформацияПоТипу.TryGetValue(type,out ИТ))
            {
                ИТ = new ИнформацияОТипе(type);
                ИнформацияПоТипу[type] = ИТ;


            }
            return ИТ;
        }
       public ИнфoрмацияОМетоде(T MI)
        {
            Method = MI;

            ParameterInfo[] parameters = Method.GetParameters();
            hasParams = false;
            КоличествоПараметров = parameters.Length;
            if (КоличествоПараметров > 0)
            { 
                hasParams = parameters[parameters.Length - 1].GetCustomAttributes(typeof(ParamArrayAttribute), false).GetEnumerator().MoveNext();
            }

            if (hasParams)
            {
                TypeParams = parameters[parameters.Length - 1].ParameterType.GetElementType();
                ИнформацияОТипеЭлемента = ПолучитьИнформациюОТипе(TypeParams);

            }

            Параметры = new ИнформацияОТипе[КоличествоПараметров];

            for(int i=0;i< parameters.Length;i++)
            {

                Параметры[i] = ПолучитьИнформациюОТипе(parameters[i].ParameterType);

            }
        }

       public ИнфoрмацияОМетоде(ИнфoрмацияОМетоде<T> ИМ, int КолПарам)
        {
            Method = ИМ.Method;
            КоличествоПараметров = КолПарам;
            КоличествоПараметровПарамс = ИМ.КоличествоПараметров;
            hasParams = true;
            TypeParams = ИМ.TypeParams;
            ИнформацияОТипеЭлемента = ИМ.ИнформацияОТипеЭлемента;

            Параметры = new ИнформацияОТипе[КолПарам];

            for (int i = 0; i < КоличествоПараметровПарамс - 1; i++)
            {

                Параметры[i] =ИМ.Параметры[i];

            }

            
            var ИОТ= ПолучитьИнформациюОТипе(ИМ.TypeParams);

            for (int i = КоличествоПараметровПарамс - 1; i < КолПарам; i++)
            {

                Параметры[i] = ИОТ;

            }
        }

        // Добавить парамс как обычный метод
        public ИнфoрмацияОМетоде(ИнфoрмацияОМетоде<T> ИМ)
        {
            Method = ИМ.Method;
            КоличествоПараметров = ИМ.КоличествоПараметров;
            КоличествоПараметровПарамс = 0;
            hasParams = false;


            Параметры = ИМ.Параметры;
        }

        public bool Сравнить(Type[] параметры)
        {

            for (int i = 0; i < КоличествоПараметров ; i++)
            {

                if (!Параметры[i].Равняется(параметры[i]))
                      return false;

            }

            return true;
        }


       
        public bool СравнитьПарамс(Type[] параметры)
        {
           var ПоследнийПарам = КоличествоПараметров - 1;

            if (параметры.Length < ПоследнийПарам)
                return false;

            for (int i = 0; i < ПоследнийПарам; i++)
            {

                if (!Параметры[i].Равняется(параметры[i]))
                    return false;

            }

            
            
            
            for (int i = ПоследнийПарам; i < параметры.Length; i++)
            {

                if ( !ИнформацияОТипеЭлемента.Равняется(параметры[i]))
                    return false;

            }

            return true;
        }

        public object ВыполнитьМетод(object Target, params object[] input)
        {

            if (!hasParams)
                return Method.Invoke(Target, input);


            int последняяПозиция = КоличествоПараметров - 1;

                object[] realParams = new object[КоличествоПараметров];
                for (int i = 0; i < последняяПозиция; i++)
                    realParams[i] = input[i];

                
                Array массивПараметров = Array.CreateInstance(TypeParams, input.Length - последняяПозиция);
                for (int i = 0; i < массивПараметров.Length; i++)
                массивПараметров.SetValue(input[i + последняяПозиция], i);

                realParams[последняяПозиция] = массивПараметров;



            var res= Method.Invoke(Target, realParams);

            массивПараметров = (Array)realParams[последняяПозиция];
            for (int i = 0; i < массивПараметров.Length; i++)
                input[i + последняяПозиция] = realParams.GetValue(i);


            return res;


        }

    }
}



Тип для IsByRef узнаем через GetElementType();
var tint = typeof(int).MakeByRefType().GetElementType();



Для примера с CallA создаем массив по параметрам.
Для методов params разврачиваем params в массив параметров но нужного количества. В примере с
static public void CallA(params int[] args)


разворачиваем до
static public void CallA(int arg1,int arg1)



Если аргументы равны, то сравниваем сначала по params, а затем по количеству аргументов (сначала идут с большим аргументом)
То есть
static public void CallA(int arg1,params int[] args)
идет раньше, чем
static public void CallA(params int[] args)
и солнце б утром не вставало, когда бы не было меня
Отредактировано 15.06.2016 7:38 Serginio1 . Предыдущая версия . Еще …
Отредактировано 14.06.2016 13:53 Serginio1 . Предыдущая версия .
Отредактировано 10.06.2016 6:57 Serginio1 . Предыдущая версия .
Отредактировано 09.06.2016 12:02 Serginio1 . Предыдущая версия .
Отредактировано 09.06.2016 11:57 Serginio1 . Предыдущая версия .
Отредактировано 09.06.2016 11:01 Serginio1 . Предыдущая версия .
Отредактировано 09.06.2016 8:41 Serginio1 . Предыдущая версия .
Отредактировано 09.06.2016 8:35 Serginio1 . Предыдущая версия .
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.