Вопрос

Прежде всего, извините, если это было спросили ранее. Я сделал довольно полный поиск и не нашел ничего подобного, но я, возможно, что -то пропустил.

А теперь к вопросу: я пытаюсь вызвать конструктора через размышления, без повезло. По сути, у меня есть объект, который я хочу клонировать, поэтому я смотрю конструктор копирования для его типа, а затем хочу его вызвать. Вот что у меня есть:

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);
    }

}

А потом я позвонил ClonerMethodS. invoke о том, что я нашел в словаре. Я не добавил код сделки со всем этим, потому что ответ, который я искал ConstructorInfo с использованием MethodBaseS. 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;
    }
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top