MethodBaseがコンストラクターにInvokeを呼び出す(反射)
-
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);
さて、私が使用しているInvokeメソッドに注意してください MethodBase
呼び出し。 ConstructorInfo
このように呼び出された場合に機能するInvokeメソッドを提供します。
return ((ConstructorInfo) method).Invoke(new object[] { toClone });
しかし、私は使いたいです MethodBase
の方法は、実際にはコピーコンストラクターを辞書に保存するたびにコピーコンストラクターを調べるのではなく、辞書にはメソッドとコンストラクターの両方が含まれているため、 Dictionary<MethodBase>
, 、 いいえ Dictionary<ConstructorInfo>
。もちろんキャストできました ConstructorInfo
上記のように、キャストを避けて使用したい MethodBase
メソッド直接。正しいパラメーターを理解できません。
何か助けがありますか?本当にありがとう。
編集
ベンジャミン、
あなたの提案をどうもありがとう。私は実際にあなたが2回目の編集で提案したことを正確にやっていたが、それを除いて(そしてそれは大きな「除く」)私の辞書はどこにあったか
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<,>
, 、そして、私が忘れていたラムダのオペレーターについて知っていたら(私は以前にこのようなものが本当に必要だったことはありませんでした)、私は実際にあなたの答えから多くを学びました。私はいつも新しいことを学ぶのが大好きで、これは将来非常に便利になるので、どうもありがとう! :)
解決
オブジェクトがそのようなコンストラクターを持っていることを知っているなら、あなたはこの過負荷を使用することを考えましたか? Activator.CreateInstance
代わりは?
更新:したがって、MethodInfo/MethodBaseのカスケード検索が既にあり、それらを保存しています - >あなたは望んでいない/使用できません Activator
.
その場合、私はあなたがキャストなしでやりたいことをする方法を見ていません。しかし - 多分あなたはアーキテクチャを変更して保存することができます Dictionary<Type, Func<object, object>>
それらを追加します Func<>
代わりにインスタンス。呼び出しコードをより良くし(私は想定します)、これを1回行うことができます。
// 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;
}
}