Призыв метод базы на конструкторе (отражение)
-
23-09-2019 - |
Вопрос
Прежде всего, извините, если это было спросили ранее. Я сделал довольно полный поиск и не нашел ничего подобного, но я, возможно, что -то пропустил.
А теперь к вопросу: я пытаюсь вызвать конструктора через размышления, без повезло. По сути, у меня есть объект, который я хочу клонировать, поэтому я смотрю конструктор копирования для его типа, а затем хочу его вызвать. Вот что у меня есть:
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
Предоставляет метод вызова, который работает, если призван так:
return ((ConstructorInfo) method).Invoke(new object[] { toClone });
Однако я хочу использовать MethodBase
Метод, потому что в действительности вместо того, чтобы просматривать конструктор копирования каждый раз, когда я буду хранить его в словаре, а в словаре содержится как методы, так и конструкторы, так что это Dictionary<MethodBase>
, нет Dictionary<ConstructorInfo>
Анкет Я, конечно, мог бросить на ConstructorInfo
Как и я выше, но я бы предпочел избегать кастинга и использовать MethodBase
Метод напрямую. Я просто не могу выяснить правильные параметры.
Любая помощь? Спасибо большое.
РЕДАКТИРОВАТЬ
Бенджамин,
Большое спасибо за ваши предложения. Я на самом деле делал именно то, что вы предлагаете во втором редактировании, кроме (и это большое «кроме»), мой словарь был там, где
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
о том, что я нашел в словаре. Я не добавил код сделки со всем этим, потому что ответ, который я искал ConstructorInfo
с использованием MethodBase
S. Invoke
Метод, поэтому я не хотел добавлять ненужную информацию и слишком много кода для вас, ребята, чтобы прочитать. Однако мне нравится ваше использование Func<,>
Гораздо лучше, поэтому я переключаюсь на это. Также делая Clone
Method Generic-это хорошее дополнение, но в моем случае вызывающий абонент не знает типа объекта, поэтому вместо этого я буду держать его не генеральным.
Я не знал о Func<,>
, и если бы я знал об операторе Lambda, которого я забыл (мне действительно не нужно было что -то подобное), поэтому я действительно многому научился из вашего ответа. Я всегда люблю изучать новые вещи, и в будущем это будет очень удобно, так что большое спасибо! :)
Решение
Если вы знаете, что у объекта есть такой конструктор, вы думали об использовании этой перегрузки Activator.CreateInstance
вместо?
ОБНОВЛЕНИЕ: Итак, у вас уже есть каскадный поиск методики/метода базы и храните их -> Вы не хотите/не можете использовать 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;
}
}