0

リフレクションを通じてデータを取得するための次のコードに直面しています。

public object GetValue(object source)
{
    if (Member == null) return Argument;
    try
    {
        object[] argList = (Argument == null ? null : new object[] { Argument });
        if (Member is PropertyInfo) return ((PropertyInfo)Member).GetValue(source, argList);
        if (Member is MethodInfo) return ((MethodInfo)Member).Invoke(source, argList);
        if (Member is FieldInfo) return ((FieldInfo)Member).GetValue(source);
        throw new Exception("Unknown member type: " + Member);
    }
    catch (Exception ex)
    {
        throw new Exception("Could not get value " + Member.Name + " from " + source + " with " + Argument, ex);
    }
}

ただし、これは非常に遅いため、リフレクションをより高速なもの、おそらくデリゲートに置き換えることを考えていますか? ただし、デリゲートが最適な選択であるか、この場合の実装方法はわかりません。.NET 4.0 を実行しています。どんな提案でも大歓迎です!

4

1 に答える 1

1

これは少し速いです

static Func<object, object[], object> BuildCaller(MethodInfo method)
{
    var obj = Expression.Parameter(typeof(object));
    var pars = Expression.Parameter(typeof(object[]));

    var pars2 = method.GetParameters();

    var casted = new Expression[pars2.Length];

    for (int i = 0; i < pars2.Length; i++)
    {
        casted[i] = Expression.Convert(Expression.ArrayAccess(pars, Expression.Constant(i)), pars2[i].ParameterType);
    }

    var call = Expression.Call(Expression.Convert(obj, method.DeclaringType), method, casted);
    var cast = Expression.Convert(call, typeof(object));
    var lamdba = Expression.Lambda<Func<object, object[], object>>(cast, obj, pars);
    return lamdba.Compile();
}

static Func<object, object[], object> BuildCaller(FieldInfo field)
{
    var obj = Expression.Parameter(typeof(object));
    var pars = Expression.Parameter(typeof(object[]));

    var call = Expression.Field(Expression.Convert(obj, field.DeclaringType), field);
    var cast = Expression.Convert(call, typeof(object));
    var lamdba = Expression.Lambda<Func<object, object[], object>>(cast, obj, pars);
    return lamdba.Compile();
}

static Func<object, object[], object> BuildCaller(PropertyInfo property)
{
    var obj = Expression.Parameter(typeof(object));
    var pars = Expression.Parameter(typeof(object[]));

    var pars2 = property.GetIndexParameters();

    var casted = new Expression[pars2.Length];

    for (int i = 0; i < pars2.Length; i++)
    {
        casted[i] = Expression.Convert(Expression.ArrayAccess(pars, Expression.Constant(i)), pars2[i].ParameterType);
    }

    var call = Expression.Property(Expression.Convert(obj, property.DeclaringType), property, casted);
    var cast = Expression.Convert(call, typeof(object));
    var lamdba = Expression.Lambda<Func<object, object[], object>>(cast, obj, pars);
    return lamdba.Compile();
}

メソッドをプリキャッシュするデリゲートを ( Expressions を介して) 作成します。「修正済み」の場合Argumentsは、さらに一歩進んで、変換もプリキャッシュできます (メソッドが呼び出されるたびに変換が行われるため)。

これはメソッドの例です。プロパティとフィールドの場合も同様です (フィールドの場合はさらに簡単です)。

そして使用例

var fun = BuildCaller(typeof(MyClass).GetMethod("MyMethod"));
var mc = new MyClass();
fun(mc, new object[] { 1, 2.0 });

fun一緒にキャッシュする必要がありますMethod

于 2013-09-13T15:09:24.963 に答える