Вызов Invoke MethodBase для конструктора (отражение)
Прежде всего, извините, если об этом уже спрашивали. Я провел довольно сложный поиск и ничего подобного не нашел, но, возможно, что-то упустил.
А теперь к вопросу: я пытаюсь вызвать конструктор через рефлексию, но безуспешно. По сути, у меня есть объект, который я хочу клонировать, поэтому я ищу конструктор копирования по его типу и затем хочу вызвать его. Вот что у меня есть:
public Object clone(Object toClone) {
MethodBase copyConstructor = type.GetConstructor(
new Type[] { toClone.GetType() });
return method.Invoke(toClone, new object[] { toClone }); //<-- doesn't work
}
Я называю описанный выше метод так:
List<int> list = new List<int>(new int[] { 0, 1, 2 });
List<int> clone = (List<int>) clone(list);
Теперь обратите внимание на метод вызова, который я использую, MethodBase
ссылаться. ConstructorInfo
предоставляет метод invoke, который работает, если вызывается так:
return ((ConstructorInfo) method).Invoke(new object[] { toClone });
Тем не менее, я хочу использовать MethodBase
Это метод, потому что на самом деле вместо поиска конструктора копирования каждый раз я буду хранить его в словаре, а словарь содержит как методы, так и конструкторы, так что это Dictionary<MethodBase>
не Dictionary<ConstructorInfo>
, Я мог бы, конечно, бросить ConstructorInfo
как я делаю выше, но я бы предпочел избежать кастинга и использовать MethodBase
метод напрямую. Я просто не могу понять правильные параметры.
Любая помощь? Спасибо.
РЕДАКТИРОВАТЬ
Benjamin,
Большое спасибо за ваши предложения. На самом деле я делал именно то, что вы предлагаете в своем втором редактировании, за исключением (и это большое "кроме") мой словарь был где
class ClonerMethod {
public MethodBase method;
public bool isConstructor;
...
public Object invoke(Object toClone) {
return isConstructor ?
((ConstructorInfo) method).Invoke(new object[] { toClone }) : //<-- I wanted to avoid this cast
method.Invoke(toClone, null);
}
}
И тогда я позвонил ClonerMethod
"s invoke
на то, что я нашел в словаре. Я не добавил код, ко всему этому относится сделка, потому что я искал ответ, как просто вызвать Invoke на ConstructorInfo
с помощью MethodBase
"s Invoke
метод, поэтому я не хотел добавлять ненужную информацию и слишком много кода для вас, ребята, чтобы прочитать. Тем не менее, мне нравится ваше использование Func<,>
Гораздо лучше, так что я перехожу на это. Также делает Clone
Метод generic является хорошим дополнением, но в моем случае вызывающая сторона не знает тип объекта, поэтому я оставлю его не универсальным.
Я не знал о Func<,>
и если бы я знал о лямбда-операторе, то забыл (мне действительно не нужно было что-то подобное раньше), поэтому я действительно многому научился из вашего ответа. Я всегда люблю изучать новые вещи, и это очень пригодится в будущем, поэтому большое спасибо!:)
1 ответ
Если вы знаете, что объект имеет такой конструктор, задумывались ли вы об использовании этой перегрузки Activator.CreateInstance
вместо?
Обновление: у вас уже есть каскадный поиск для MethodInfo/MethodBase, и вы сохраняете их -> Вы не хотите / не можете использовать Activator
,
В этом случае я не вижу способа делать то, что вы хотите без актеров. Но - может быть, вы могли бы изменить архитектуру для хранения Dictionary<Type, Func<object, object>>
и добавить эти Func<>
экземпляры вместо. Делает вызывающий код приятнее (я полагаю) и позволит вам выполнить это приведение один раз:
// Constructor
dictionary.Add(type,
source => ((ConstructorInfo) method).Invoke(new object[] {source})
);
// Clone
dictionary.Add(type,
source => method.Invoke(source, new object[]{})
);
На самом деле, поскольку вы заботитесь только о разнице между конструктором и обычным методом на том самом месте, где вы их захватываете, вам вообще не понадобится приведение, не так ли?
// Constructor 2
dictionary.Add(type,
source => yourConstructorInfo.Invoke(new object[] {source})
);
Если бы я не пропустил что-то (вполне возможно, конечно), это могло бы решить проблему, выполнив это однажды на определяющей стороне забора, и вызывающему абоненту не нужно будет возражать, если это конструктор или нет?
В последний раз я собираюсь остановить редактирование спама. Мне было скучно, и я придумал следующий код. Это то, что вы пытаетесь достичь?
public class Cloner {
private readonly IDictionary<Type, Func<object, object>> _cloneMap =
new Dictionary<Type, Func<object, object>>();
public T Clone<T>(T source) {
Type sourceType = source.GetType();
Func<object, object> cloneFunc;
if (_cloneMap.TryGetValue(sourceType, out cloneFunc)) {
return (T)cloneFunc(source);
}
if (TryGetCopyConstructorCloneFunc(sourceType, out cloneFunc)) {
_cloneMap.Add(sourceType, cloneFunc);
return (T)cloneFunc(source);
}
if (TryGetICloneableCloneFunc(sourceType, out cloneFunc)) {
_cloneMap.Add(sourceType, cloneFunc);
return (T)cloneFunc(source);
}
return default(T);
}
private bool TryGetCopyConstructorCloneFunc(Type type,
out Func<object, object> cloneFunc) {
var constructor = type.GetConstructor(new[] { type });
if (constructor == null) {
cloneFunc = source => null;
return false;
}
cloneFunc = source => constructor.Invoke(new[] { source });
return true;
}
private bool TryGetICloneableCloneFunc(Type type,
out Func<object, object> cloneFunc) {
bool isICloneable = typeof(ICloneable).IsAssignableFrom(type);
var cloneMethod = type.GetMethod("Clone", new Type[] { });
if (!isICloneable || (cloneMethod == null)) {
cloneFunc = source => null;
return false;
}
cloneFunc = source => cloneMethod.Invoke(source, new object[] {});
return true;
}
}