質問

文字列を指定すると:「Person.Address.Postcode」 Person のインスタンスでこの郵便番号プロパティを取得/設定できるようにしたいと考えています。これどうやってするの?私のアイデアは、文字列を「」で分割することでした。そして、以前のタイプのプロパティを探して、部品を反復し、そのようなものに見える式ツリーを構築します(擬似構文について謝罪):

(person => person.Address) address => address.Postcode

ただし、実際に式ツリーを作成するのに非常に苦労しています。これが最善の方法である場合、誰かがその方法を提案してもらえますか、またはより簡単な代替方法はありますか?

ありがとう

アンドリュー

public class Person
{
    public int Age { get; set; }
    public string Name { get; set; }
    public Address Address{ get; set; }

    public Person()
    {
        Address = new Address();
    }
}

public class Address 
{
    public string Postcode { get; set; }
}
役に立ちましたか?

解決

なぜあなたは再帰を使用していませんか?ような何かます:

setProperyValue(obj, propertyName, value)
{
  head, tail = propertyName.SplitByDotToHeadAndTail(); // Person.Address.Postcode => {head=Person, tail=Address.Postcode}
  if(tail.Length == 0)
    setPropertyValueUsingReflection(obj, head, value);
  else
    setPropertyValue(getPropertyValueUsingReflection(obj, head), tail, value); // recursion
}

他のヒント

正則リフレクションでソートされているように見えますが、ネストされたプロパティの式を構築するコードは次のようになります。 このオーダーバイコード.

値を設定するには、次を使用する必要があることに注意してください。 GetSetMethod() プロパティ上でそれを呼び出します - 構築後に値を割り当てるための組み込み式はありません (ただし、 4.0でサポートされました).

次のように(編集):

using System;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
class Foo
{
    public Foo() { Bar = new Bar(); }
    public Bar Bar { get; private set; }
}
class Bar
{
    public string Name {get;set;}
}
static class Program
{
    static void Main()
    {
        Foo foo = new Foo();
        var setValue = BuildSet<Foo, string>("Bar.Name");
        var getValue = BuildGet<Foo, string>("Bar.Name");
        setValue(foo, "abc");
        Console.WriteLine(getValue(foo));        
    }
    static Action<T, TValue> BuildSet<T, TValue>(string property)
    {
        string[] props = property.Split('.');
        Type type = typeof(T);
        ParameterExpression arg = Expression.Parameter(type, "x");
        ParameterExpression valArg = Expression.Parameter(typeof(TValue), "val");
        Expression expr = arg;
        foreach (string prop in props.Take(props.Length - 1))
        {
            // use reflection (not ComponentModel) to mirror LINQ 
            PropertyInfo pi = type.GetProperty(prop);
            expr = Expression.Property(expr, pi);
            type = pi.PropertyType;
        }
        // final property set...
        PropertyInfo finalProp = type.GetProperty(props.Last());
        MethodInfo setter = finalProp.GetSetMethod();
        expr = Expression.Call(expr, setter, valArg);
        return Expression.Lambda<Action<T, TValue>>(expr, arg, valArg).Compile();        

    }
    static Func<T,TValue> BuildGet<T, TValue>(string property)
    {
        string[] props = property.Split('.');
        Type type = typeof(T);
        ParameterExpression arg = Expression.Parameter(type, "x");
        Expression expr = arg;
        foreach (string prop in props)
        {
            // use reflection (not ComponentModel) to mirror LINQ 
            PropertyInfo pi = type.GetProperty(prop);
            expr = Expression.Property(expr, pi);
            type = pi.PropertyType;
        }
        return Expression.Lambda<Func<T, TValue>>(expr, arg).Compile();
    }
}

だが、性能はトレードオフの関係に 単純反射 アプローチも良事例 こちらのこちらの)、Marcの 現ビル アプローチ...

私の試験に関わって比較的深い性(A.B.C.D.E)10,000ます。

  1. 振り:64ms
  2. 表現棟1684ms

このように、非常に特定の試験、なんと考えoptimisationsまたはプロパティの設定だと思うんで26倍パフォーマンスは注目に値する。

あなたはのTypeConverterまたは他のソースで独自のPropertyDescriptorのを提供することを見てみたい。

私はあなたのBindingSourceから派生し、そこを経由して情報を提供することで、(申し訳ありませんが、商用、他の私が共有する)現在のプロジェクトの説明を正確に何を実装しました。

次のように

アイデアがあります:

あなたがする必要があるすべては、あなたがタイプは少しを作成することですしたら、あるプロパティのゲッターとセッターのための「スタック」、そしてあなたがタイプとそのプロパティのプロパティツリーを歩い経由で収集することができ、これらは限定的なもの、幅優先指定されたレベルの数と、あなたのデータ構造に応じて、循環参照を除去する深ます。

私はLinq2SQLオブジェクトとし、それらの結合リストとの組み合わせで非常に成功し、これを使用しています:)

式ツリー

struct tree
{
    char info;
    struct tree *rchild;
    struct tree *lchild;
};

int prec(char data);

typedef struct tree * node;

char pop_op();
node pop_num();
void push_op(char item);

node create()
{
    return((node)malloc(sizeof(node)));
}

node num[20],root=NULL;
char op[20],oprt,ev[20];
int nt=-1,ot=-1,et=-1;

main()
{
    node newnode,item,temp;
    char str[50];
    int i,k,p,s,flag=0;
    printf("ENTER THE EXPRESSION ");
    scanf("%s",str);
    printf("\n%s",str);
    for(i=0;str[i]!='\0';i++)
    {
        if(isalnum(str[i]))
        {
            newnode=create();
            newnode->info=str[i];
            newnode->lchild=NULL;
            newnode->rchild=NULL;
            item=newnode;
            push_num(item);
        }
        else
        {
            if(ot!=-1)
                p=prec(op[ot]);
            else
                p=0;
            k=prec(str[i]);
            if(k==5)
            {
                while(k!=1)
                {
                    oprt=pop_op();
                    newnode=create();
                    newnode->info=oprt;
                    newnode->rchild=pop_num();
                    newnode->lchild=pop_num();
                    // if(root==NULL)
                    root=newnode;
                    // else if((newnode->rchild==root)||(newnode->lchild==root))
                    // root=newnode;
                    push_num(root);
                    k=prec(op[ot]);
                }
                oprt=pop_op();
            }
            else if(k==1)
                push_op(str[i]);
            else
            {
                if(k>p)
                    push_op(str[i]);
                else
                {
                    if(k<=p)
                    {
                        oprt=pop_op();
                        newnode=create();
                        newnode->rchild=pop_num();
                        newnode->lchild=pop_num();
                        if(root==NULL)
                        root=newnode;
                        else if((newnode->rchild==root)||(newnode->lchild==root))
                        root=newnode;
                        push_num(newnode);
                        push_op(str[i]);
                        // k=prec(op[ot]);
                    }
                }
            }
        }
    }
    printf("\nThe prefix expression is\n ");
    preorder(root);
    printf("\nThe infix exp is\n ");
    inorder(root);
    printf("\nThe postfix expression is\n ");
    postorder(root);
    evaluate();
}
void push_op(char item)
{
    op[++ot]=item;
}
push_num(node item)
{
    num[++nt]=item;
}
char pop_op()
{
    if(ot!=-1)
    return(op[ot--]);
    else
    return(0);
}
node pop_num()
{
    if(nt!=-1)
    return(num[nt--]);
    else
    return(NULL);
}
int prec(char data)
{
    switch(data)
    {
        case '(':return(1);
            break;
        case '+':
        case '-':return(2);
            break;
        case '*':
        case '/':return(3);
            break;
        case '^':return(4);
            break;
        case ')':return(5);
            break;
    }
}


inorder(node temp)
{
    if(temp!=NULL)
    {
        inorder(temp->lchild);
        printf("%c ",temp->info);
        inorder(temp->rchild);
    }
}

preorder(node temp)
{
    if(temp!=NULL)
    {
        printf("%c ",temp->info);
        preorder(temp->lchild);
        preorder(temp->rchild);
    }
}

postorder(node temp)
{
    if(temp!=NULL)
    {
        postorder(temp->lchild);
        postorder(temp->rchild);
        printf("%c ",temp->info);
        ev[++et]=temp->info;
    }
}
evaluate()
{
    int i,j=-1,a,b,ch[20];
    for(i=0;ev[i]!='\0';i++)
    {
        if(isalnum(ev[i]))
            ch[++j]=ev[i]-48;
        else
        {
            b=ch[j];
            a=ch[j-1];
            switch(ev[i])
            {
                case '+':ch[--j]=a+b;
                    break;
                case '-':ch[--j]=a-b;
                    break;
                case '*':ch[--j]=a*b;
                    break;
                case '/':ch[--j]=a/b;
                    break;
            }
        }
    }
    printf("\nValue = %d",ch[0]);
}
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top