在构造函数上调用MethodBase的Invoke(反射)

时间:2010-03-30 08:17:51

标签: c# reflection constructor 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提供了一个调用方法,如果像这样调用它可以工作:

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的{​​{1}}。我没有添加代码处理所有这些因为我正在寻找的答案是如何使用invoke的{​​{1}}方法调用ConstructorInfo上的Invoke,所以我没有我想添加不必要的信息和太多的代码供你们阅读。但是,我更喜欢你使用MethodBase,所以我改用它。同样使Invoke方法通用是一个很好的补充,但在我的情况下,调用者不知道对象的类型,所以我将保持非泛型。

我不知道Func<,>,如果我知道我忘记的lambda算子(之前我没有真正需要这样的东西),所以我从你的回答中学到了很多东西。我总是喜欢学习新东西,这将在未来非常方便,所以非常感谢! :)

1 个答案:

答案 0 :(得分:4)

如果你知道对象有这样的构造函数,你是否考虑过使用Activator.CreateInstance的重载?


更新:所以你已经对MethodInfo / MethodBase进行级联搜索并存储它们 - &gt;您不希望/不能使用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;
    }
}