3

私が取り組んでいるものに少し問題があります。最初に、ビジネス オブジェクトと正常に機能しているデータ アクセス レイヤーの間に位置するジェネリック レイヤーを作成しました。その後、最近、エクスプレッション ツリーと呼ばれるものについて読みました。これは明らかに効率的であり、Activator.CreateInstance() をエクスプレッションに交換し、ジェネリック レイヤーが指数関数的に改善されたことが証明されています。

私はまだ領域全体(式)についていくつか読んでいますが、汎用的にしようとするコードに出くわしました。現時点では、string、int、decimal などの具体的な型を渡す必要があります。私はこのビットを一般的なものにしました。いくつか試してみましたが失敗しました。ジェネリックが必要なビットはアクションです。プロパティのタイプをジェネリックに渡すことができるようにしたい文字列を渡したくありません。つまり、typeof(T).GetProperty("Forename").PropertyTypeです。これは可能ですか?ちょっとしたフーバーであるswitch文をやろうと思っていました。

前もってありがとう、オナム。

public class TTT<T> where T : new()
{
    public void Do(object t)
    {
        MethodInfo info = typeof(T).GetProperty("Forename").GetSetMethod();

        ParameterExpression param = Expression.Parameter(typeof(string), "val");

        MethodCallExpression call = Expression.Call(Expression.Constant(t), info,
            new ParameterExpression[] { param });

        Action<string> action = Expression.Lambda<Action<string>>(call, param).Compile();

        action("hi");
    }
}
4

1 に答える 1

5

まず、これは良い方法ではないことに注意してください。Expression呼び出しごとを構築し、それをCompile()-ing してから呼び出す場合、パフォーマンス上の利点はありません。反射は速くなります。パフォーマンスが必要な場合は、次のような"FastMember"などのライブラリを見てください。

var accessor = TypeAccessor.Create(typeof(T));
accessor[target, "Forename"] = value;

(メタプログラミングと自動キャッシュによって完全に最適化されている場合)


タイプを動的にしたい場合は、次の 2 つのオプションがあります。

  • 使用して入力してExpression.GetActionType使用するDynamicInvoke-本当にパフォーマンスが悪い (ヒント: これをしないでください)
  • asAction<object>と入力し、式の中でキャストを行います (細かい)

次のようなものです:

using System;
using System.Linq.Expressions;
using System.Reflection;
class Foo
{
    public string Forename {get;set;}
}
class Test<T>
{
    public void Do(object target, object value)
    {
        var obj = Expression.Constant(target, typeof(T));
        var member = Expression.PropertyOrField(obj, "Forename");
        var param = Expression.Parameter(typeof(object));
        Type type;
        switch(member.Member.MemberType)
        {
            case MemberTypes.Field:
                type = ((FieldInfo)member.Member).FieldType; break;
            case MemberTypes.Property:
                type = ((PropertyInfo)member.Member).PropertyType; break;
            default:
                throw new NotSupportedException(member.Member.MemberType.ToString());
        }
        var body = Expression.Assign(member, Expression.Convert(param, type));
        var lambda = Expression.Lambda<Action<object>>(body, param);
        lambda.Compile()(value);
    }
}
static class Program
{
    static void Main()
    {
        var obj = new Foo();
        new Test<Foo>().Do(obj, "abc");
        Console.WriteLine(obj.Forename);
    }
}
于 2012-11-16T10:03:11.590 に答える