Сообщение Re[12]: Приоритет вызова перегруженных методов от 09.06.2016 7:13
Изменено 15.06.2016 7:38 Serginio1
Здравствуйте, Sinix, Вы писали:
S>Не вопрос, как сделаете корректное разруливание перегрузок по значениям аргументов в GetMethod() — так сразу и приходите.
Идея такая создаем класс для сравнения
Тип для IsByRef узнаем через GetElementType();
Для примера с CallA создаем массив по параметрам.
Для методов params разврачиваем params в массив параметров но нужного количества. В примере с
разворачиваем до
Если аргументы равны, то сравниваем сначала по params, а затем по количеству аргументов (сначала идут с большим аргументом)
То есть
static public void CallA(int arg1,params int[] args)
идет раньше, чем
static public void CallA(params int[] args)
S>Не вопрос, как сделаете корректное разруливание перегрузок по значениям аргументов в GetMethod() — так сразу и приходите.
Идея такая создаем класс для сравнения
namespace CoreClrDLL
{
public class ИнформацияОТипе: IComparable<ИнформацияОТипе>
{
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;
Параметры = new ИнформацияОТипе[КолПарам];
for (int i = 0; i < КоличествоПараметровПарамс - 1; i++)
{
Параметры[i] =ИМ.Параметры[i];
}
var ИОТ= ПолучитьИнформациюОТипе(ИМ.TypeParams);
for (int i = КоличествоПараметровПарамс - 1; i < КолПарам; i++)
{
Параметры[i] = ИОТ;
}
}
public bool Сравнить(Type[] параметры)
{
for (int i = 0; i < КоличествоПараметров ; i++)
{
if (!Параметры[i].Равняется(параметры[i]))
return false;
}
return true;
}
public bool СравнитьПарамс(Type[] параметры)
{
if (параметры.Length < КоличествоПараметров - 1)
return false;
for (int i = 0; i < КоличествоПараметров - 1; i++)
{
if (!Параметры[i].Равняется(параметры[i]))
return false;
}
for (int i = КоличествоПараметров - 1; i < параметры.Length; i++)
{
if ( !ИнформацияОТипеЭлемента.Равняется(параметры[i]))
return false;
}
return true;
}
}
}
Тип для 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)
Re[12]: Приоритет вызова перегруженных методов
Здравствуйте, Sinix, Вы писали:
S>Не вопрос, как сделаете корректное разруливание перегрузок по значениям аргументов в GetMethod() — так сразу и приходите.
Идея такая создаем класс для сравнения
Тип для IsByRef узнаем через GetElementType();
Для примера с CallA создаем массив по параметрам.
Для методов params разврачиваем params в массив параметров но нужного количества. В примере с
разворачиваем до
Если аргументы равны, то сравниваем сначала по params, а затем по количеству аргументов (сначала идут с большим аргументом)
То есть
static public void CallA(int arg1,params int[] args)
идет раньше, чем
static public void CallA(params int[] args)
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)