3

まず、これが以前に尋ねられた場合は申し訳ありません。私はかなり包括的な検索を行いましたが、それとまったく同じものは見つかりませんでしたが、何かを見落としている可能性があります.

そして今、質問に: リフレクションを介してコンストラクターを呼び出そうとしていますが、運がありません。基本的に、複製したいオブジェクトがあるので、その型のコピー コンストラクターを検索し、それを呼び出します。ここに私が持っているものがあります:

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メソッドを直接使用したいと思います。正しいパラメータがわかりません。

何か助けはありますか?本当にありがとう。


編集

ベンジャミン、
あなたの提案に感謝します。私は実際にあなたが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私が探していた答えは、ConstructorInfousingMethodBaseInvokeメソッドで Invoke を呼び出す方法だけだったので、それらすべてを処理するコードを追加しませんでした。読んでください。しかし、私はあなたの使い方がFunc<,>ずっと良いと思うので、そちらに切り替えます。また、Cloneメソッドをジェネリックにするのは良い追加ですが、私の場合、呼び出し元はオブジェクトの型を知らないので、代わりに非ジェネリックのままにします。

私は について知らなかったしFunc<,>、忘れていたラムダ演算子について知っていれば(以前はこのようなものは本当に必要ではなかった)、実際にあなたの答えから多くのことを学びました。私はいつも新しいことを学ぶのが大好きで、これは将来とても役に立ちます。どうもありがとうございました! :)

4

1 に答える 1

4

オブジェクトがそのようなコンストラクターを持っていることを知っている場合、Activator.CreateInstance代わりにこのオーバーロードを使用することを考えましたか?


更新:したがって、既に MethodInfo/MethodBase のカスケード検索があり、それらを保存しています -> したくない/使用できませんActivator

その場合、キャストなしでやりたいことを行う方法がわかりません。しかし、アーキテクチャを変更して a を保存し、代わりにそれらのインスタンス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})
);

私が何かを見逃していない限り(もちろん、可能性は十分にあります)、フェンスの定義側でこれを1回実行することで問題を解決でき、呼び出し元はこれがコンストラクターであるかどうかを気にする必要はありませんか?


最後にもう一度、編集スパムを停止します。退屈して、次のコードを思いつきました。それはあなたが達成しようとしていることですか?

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;
    }
}
于 2010-03-30T08:23:29.163 に答える