32

グーグルでSOに着陸し、この他の質問を読んだ後

コンパイル時にパラメーターの数や型がわからなかった場合、MethodInfo から正しいデリゲートを作成することは可能ですか?

詳細: これは、Reflection.Emit または型ビルダーを使用せずにエレガントに実行できますか?

Delegate.CreateDelegate では、最初のパラメーターとして正しいデリゲート型を指定する必要があるため、これは私にとっては残念なことです。そうしないと、例外がスローされたり、不適切なメソッドが呼び出されたりします。

私はいくつかの忍者ギアを構築していますが、これは非常に役立ちます.ありがとう!


一般的な解決策は次のとおりです。

/// <summary>
/// Builds a Delegate instance from the supplied MethodInfo object and a target to invoke against.
/// </summary>
public static Delegate ToDelegate(MethodInfo mi, object target)
{
    if (mi == null) throw new ArgumentNullException("mi");

    Type delegateType;

    var typeArgs = mi.GetParameters()
        .Select(p => p.ParameterType)
        .ToList();

    // builds a delegate type
    if (mi.ReturnType == typeof(void)) {
        delegateType = Expression.GetActionType(typeArgs.ToArray());

    } else {
        typeArgs.Add(mi.ReturnType);
        delegateType = Expression.GetFuncType(typeArgs.ToArray());
    }

    // creates a binded delegate if target is supplied
    var result = (target == null)
        ? Delegate.CreateDelegate(delegateType, mi)
        : Delegate.CreateDelegate(delegateType, target, mi);

    return result;
}

: 私は、同じ Silverlight [ScriptableMember] メソッドを呼び出す複数の Javascript インターフェイスを持つ、何年も前に構築された JavaScript アプリケーションを置き換える Silverlight アプリケーションを構築しています。

新しい機能にアクセスするための新しいインターフェイスだけでなく、これらのすべてのレガシー JS インターフェイスもサポートする必要があるため、JS インターフェイスを自動的にセットアップし、適切な Silverlight メソッドへの呼び出しを「委譲」するものは、作業を大幅に高速化するのに役立ちます。

ここにコードを投稿することはできないので、それが要約です。

4

3 に答える 3

22

正直なところ、コンパイル時に型がわからない場合、Delegate. 使いたくないDynamicInvoke; 反射と同じくらい遅くなります。これに対する主な例外は、デリゲート型が影に潜んでいる場合です。たとえば、イベントをサブスクライブする場合です。この場合EventInfo、これが利用可能になります。

情報については、.NET 3.5 onExpressionには次のものがあります。

Expression.GetActionType(params Type[] typeArgs);
Expression.GetFuncType(params Type[] typeArgs)

それはある程度役立つかもしれません:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
static class Program {
    static void Main() {
        DoStuff("Test1");
        DoStuff("Test2");
    }
    static void DoStuff(string methodName) {
        MethodInfo method = typeof(Program).GetMethod(methodName);
        List<Type> args = new List<Type>(
            method.GetParameters().Select(p => p.ParameterType));
        Type delegateType;
        if (method.ReturnType == typeof(void)) {
            delegateType = Expression.GetActionType(args.ToArray());
        } else {
            args.Add(method.ReturnType);
            delegateType = Expression.GetFuncType(args.ToArray());
        }
        Delegate d = Delegate.CreateDelegate(delegateType, null, method);
        Console.WriteLine(d);
    }
    public static void Test1(int i, DateTime when) { }
    public static float Test2(string x) { return 0; }
}
于 2009-07-14T10:36:04.877 に答える
9

なぜそれが複雑なのですか?

public static Delegate CreateDelegate(this MethodInfo method)
{
    return Delegate.CreateDelegate
    (
        Expression.GetDelegateType
        (
            method.GetParameters()
                .Select(p => p.ParameterType)
                .Concat(new Type[] { method.ReturnType })
                .ToArray()
        ),
        null,
        method
    );   
}

[補足:このメソッドの前に「Create...」を付けました。「To...」は、それが回心だと思わせるので混乱を招きます。]

于 2010-12-28T08:43:02.320 に答える
7

パラメーターの数や型が事前にわからない場合は、おそらく、作成するデリゲートの型もわからないということでしょうか?

その場合は、絶対に一般的なケースで立ち往生しています。

ただし、ほとんどの一般的なFuncケース (ref/out パラメーターがない、既存の型のいずれかを使用するのに十分なパラメーターが少ない) では、またはActionデリゲートのいずれかを使用できます。(.NET 4.0 には膨大な数のパラメーターのFunc/Action型があるため、実際には out/ref パラメーターについて心配するだけで済みます。) メソッドに void 以外の戻り値の型がある場合は を使用しFunc、そうでない場合は を使用しますAction。パラメータの数に基づいて、使用するタイプを決定します。

static readonly Type[] FuncTypes = { typeof(Func), 
    typeof(Func<>), typeof(Func<,>), typeof(Func<,,>), /* etc */ };

パラメーターの型と戻り値の型を使用Type.MakeGenericTypeして適切なデリゲート型を取得すると、Delegate.CreateDelegate機能するはずです。

今はサンプルを作成する時間がありませんが、後で必要な場合はお知らせください.

1 つの質問: このデリゲートをどのように使用するつもりですか? 他の何かがそれを実行する方法を知る必要があります、確かに...

于 2009-07-14T10:34:10.607 に答える