20

にキャストするより速い方法はありますFun<TEntity, TId>Func<TEntity, object>

public static class StaticAccessors<TEntity>
{
 public static Func<TEntity, TId> TypedGetPropertyFn<TId>(PropertyInfo pi)
 {
  var mi = pi.GetGetMethod();
  return (Func<TEntity, TId>)Delegate.CreateDelegate(typeof(Func<TEntity, TId>), mi);
 }

 public static Func<TEntity, object> ValueUnTypedGetPropertyTypeFn(PropertyInfo pi)
 {
  var mi = typeof(StaticAccessors<TEntity>).GetMethod("TypedGetPropertyFn");
  var genericMi = mi.MakeGenericMethod(pi.PropertyType);
  var typedGetPropertyFn = (Delegate)genericMi.Invoke(null, new[] { pi });

  //slow: lambda includes a reflection call
  return x => typedGetPropertyFn.Method.Invoke(x, new object[] { }); //can we replace this?
 }
}

上記の例のように、返されたラムダにリフレクションコードを含まずにに変換する方法はありtypedGetPropertyFnますか?Func<TEntity, object>

編集:変更されたソリューションを追加

以下の最終的な解決策に含めた正しい道に私を導いてくれた280Z28に感謝します。式をサポートしていないプラットフォーム用のリフレクションコードをそこに残しました。それを行うプラットフォームの場合、取得とプロパティのパフォーマンスが26倍から27倍(平均13 / .5ティック)増加します。intstring

public static Func<TEntity, object> ValueUnTypedGetPropertyTypeFn(PropertyInfo pi)
{
    var mi = typeof(StaticAccessors<TEntity>).GetMethod("TypedGetPropertyFn");
    var genericMi = mi.MakeGenericMethod(pi.PropertyType);
    var typedGetPropertyFn = (Delegate)genericMi.Invoke(null, new[] { pi });

    #if NO_EXPRESSIONS
    return x => typedGetPropertyFn.Method.Invoke(x, new object[] { });
    #else
    var typedMi = typedGetPropertyFn.Method;
    var obj = Expression.Parameter(typeof(object), "oFunc");
    var expr = Expression.Lambda<Func<TEntity, object>> (
            Expression.Convert(
                Expression.Call(
                    Expression.Convert(obj, typedMi.DeclaringType),
                    typedMi
                ),
                typeof(object)
            ),
            obj
        );
    return expr.Compile();
    #endif
}
4

3 に答える 3

10

次のことを検討しましたか。

 Func<Foo, Bar> typed = (f) => return new Bar();
 Func<Foo, object> untyped = (f) => typed(f);

このようにして、デリゲートをラップするだけです。

于 2010-01-30T19:31:52.590 に答える
8

ご存知のように、MethodInfoからを取得できますPropertyInfo.GetGetMethod()。それから、以下を使用して、Func<object, object>そのプロパティを取得するためのを取得できます。同様の方法で、強く型付けされたを返すことができますFunc<TObject, TResult>MethodInfoこのメソッドは、結果のデリゲートを呼び出すよりも少なくとも1桁高価であるため、任意の場合に、この呼び出しの結果を複数回必要とする場合はキャッシュする必要があります。

private static Func<object, object> BuildAccessor(MethodInfo method)
{
    ParameterExpression obj = Expression.Parameter(typeof(object), "obj");

    Expression<Func<object, object>> expr =
        Expression.Lambda<Func<object, object>>(
            Expression.Convert(
                Expression.Call(
                    Expression.Convert(obj, method.DeclaringType),
                    method),
                typeof(object)),
            obj);

    return expr.Compile();
}
于 2010-01-30T19:31:03.027 に答える
6

.NET 4.0では、FuncデリゲートがTResultにout修飾子をマークするため、これを行うことができます。.NET 3.5はジェネリック共変性/反変性をサポートしていないため、単純にキャストすることはできません。リフレクションよりも速い別の賢い方法があるかどうかはわかりません。

これがFuncの.NET4.0ドキュメントページです。TResultは「out」でマークされているため、その戻り値をオブジェクトなどのあまり特定されていないタイプとしてキャストできることに注意してください。


外部依存関係がない簡単な例として、次のコードは.NET 3.5でのコンパイルに失敗しますが、.NET4.0では正しくコンパイルおよび実行されます。

// copy and paste into LINQpad
void Main()
{
    Func<int, string> func1 = GetString;
    string res1 = func1(1);
    res1.Dump();

    Func<int, object> func2 = func1;
    object res2 = func2(1);
    res2.Dump();
}

public string GetString<T>(T obj) {
    return obj.ToString();
}
于 2010-01-30T19:18:58.573 に答える