2009-02-11 38 views
11

給定一個字符串:「Person.Address.Postcode」我希望能夠在Person實例上獲取/設置此Postcode屬性。我怎樣才能做到這一點?我的想法是將字符串拆分爲「。」。然後遍歷部分,尋找前一類型的屬性,然後建立一個表達式樹看起來是這樣的(道歉僞語法):如何從字符串中爲深度屬性創建表達式樹/ lambda

(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; } 
} 

回答

2

爲什麼你不使用遞歸?喜歡的東西:

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 
} 
+0

我總是試圖過度設計一些東西。把事情簡單化!生病嘗試,ta – 2009-02-11 14:41:52

+0

只要記住,C#不是尾遞歸,所以你可能會以StackOverflow異常結束。 – 2014-04-01 17:05:19

21

這聽起來像你與正反射排序,但對信息的代碼來構建嵌套屬性的表達式將是非常相似this order-by code

請注意,要設置一個值,您需要在該屬性上使用GetSetMethod()並調用它 - 在構建後沒有內置表達式用於賦值(雖然它是supported in 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(); 
    } 
} 
+0

剛剛搜索了一個類似的話題,這首先在谷歌,並回答了我的問題:D – 2009-03-06 17:00:54

1

你想看看提供自己的PropertyDescriptor的通過類型轉換器或其他來源。

我已經實現了您對當前項目的描述(抱歉,商業,否則我會分享),從BindingSource派生,並通過那裏提供信息。

的思路如下:

所有你需要做的是,一旦你的類型是創建小的籌碼「的getter和性質的制定者,以及那些你可以通過走資源收集樹的類型及其屬性首先是寬度,將深度限制爲指定數量的級別,並根據數據結構刪除循環引用。

我用這相當成功地與LINQ2SQL對象,並結合他們的結合列表:)

-8

表達式樹

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]); 
} 
2

如果有人有興趣在性能權衡simple reflection方法之間(也很好的例子herehere)和馬克的Expression-building方法...

我的測試涉及獲得相對較深的屬性(ABCDE)10,000次。

  1. 簡單反映:64毫秒
  2. 表達建設:1684毫秒

顯然,這是一個非常具體的測試,我還沒有考慮過的優化或設置屬性,但我認爲26倍性能打擊值得注意。

相關問題