2011-10-06 80 views
1

我已經設置的屬性如下:分配領域的動態

public string Foo1 {set;get;} 
public string Foo2 {set;get;} 
public string Foo3 {set;get;} 
public string Foo4 {set;get;} 
public string Foo5 {set;get;} 
public string Foo6 {set;get;} 
public string Foo7 {set;get;} 
public string Foo8 {set;get;} 
public string Foo9 {set;get;} 
...... 
public string Foo50 {set;get;} 

然後I M迭代整個集合如下:

foreach(var element in sortedCollection.Keys){ 
    if(element != null) 
    // in this block I would like to assign the element to the properties above 
    // ex: 
    foo?? = sortedCollection[element]; 
    // ?? need to be replaced by index. 
} 

是否有一個簡單的方法來做到這一點?

+3

是否有這樣的類設計的原因? – Stefan

+0

它已經這樣設計了。不能改變它。 – DarthVader

+3

如果用反射而不是重構爲更好的設計,你可能會遇到更多麻煩......(添加反射後,很難重構/重新設計它) –

回答

5

我認爲一個更好的設計是:

public List<string> Foos { get; private set; } 

如果你不能改變它,你也許可以這樣做:

var type = typeof(MyCalss); 
int index = 1; 
foreach (var key in sortedCollection.Keys) 
{ 
    var value = sortedCollection[key]; 
    var prop = type.GetProperty("Foo" + index); 
    if (prop != null) prop.SetValue(this, value, null); 

    index++; 
} 

...當然有一些錯誤處理,並且this假定這是您班級中的一種方法。您能否根據您的sortedCollection中的值確定一個索引?

+0

不可接受。我不能改變設計。 – DarthVader

+1

那麼,作爲一種解決方法,您可以創建一個使用反射訪問Foo屬性的索引器。至少,看起來會更好。 –

+5

@ user177883:你應該抗議那些說你無法改進設計的人 - 修復像這樣糟糕的設計幾乎總是提前完成,而不是以後完成。 –

1

你可以做你想做由什麼:

  1. 使用for循環,而不是的foreach。這樣您可以使用當前索引進行操作。
  2. 使用反射。您可以獲得您班級的屬性列表並動態訪問它們。例如,請參閱Type.GetProperties

但是,您爲什麼不使用List<string> Foos而不是許多屬性?

1

你應該使用反射。

this.GetType()。GetProperty(「Foo」+ i).SetValue(this,sortedCollection [element],null);

兩件事情,但:

  • 的getProperty的成本不爲空。所以如果你這樣做了很多次,你可能想要將GetProperty的結果存儲在某個字段中,然後在你的foreach中使用這個字段。
  • 如果你的屬性真的被命名爲Something1,Something2等等,那麼你可能有一個設計缺陷,你可能想在這之前糾正(用一個List替換你所有的字符串成員)。
1

您需要使用reflection(Type.GetProperty())來獲取屬性並設置它的值。

假設屬性類稱爲MyClass的定義:

foreach(var element in sortedCollection.Keys){ 
    if(element != null) 
    // in this block I would like to assign the element to the properties above 
    // ex: 
    //foo?? = sortedCollection[element]; 
    // not sure how you are getting the index here, may be you need to use for loop 
    PropertyInfo pi = typeof(MyClass).GetProperty("Foo" + index); 

    // ?? need to be replaced by index. 
    if (pi != null) 
    { 
     pi.SetValue(<object of MyClass>, sortedCollection[element], null); 
    } 
} 
1
void Main() 
{ 
    var foo = new Foo(); 
    foo[1] = "Foo1";  
    //foo.Dump(); 
} 

public class Foo 
{ 
    public string Foo1 {set;get;} 
    public string Foo2 {set;get;} 
    public string Foo3 {set;get;} 
    public string Foo4 {set;get;} 
    public string Foo5 {set;get;} 
    public string Foo6 {set;get;} 
    public string Foo7 {set;get;} 
    public string Foo8 {set;get;} 
    public string Foo9 {set;get;} 

    public string this[int index] 
    { 
     get 
     { 
      return getPropertyValue(index); 
     } 
     set 
     { 
      setPropertyValue(index, value); 
     } 
    } 
    private void setPropertyValue(int i, string value) 
    { 
     var propi = this.GetType().GetProperty("Foo" + i); 
     if (propi != null) 
      propi.SetValue(this,value,null); 
    } 
    private string getPropertyValue(int i) 
    { 
     var propi = this.GetType().GetProperty("Foo" + i); 
     if (propi != null) 
      return (string)propi.GetValue(this, null); 
     return null; 
    } 
} 
1

我真的使用反射,或者如果這就是所謂的有很多,做一個動態的方法和ILEmit做到這一點(多在運行時比反射更快)。

但只是建議不同的東西,你可以更改包含富*屬性的類,以便各的getter/setter從索引列表如下:

public class FooOfDoom 
    { 
    public string[] Foos = new string[2]; 

    public string Foo1 
    { 
     set { Foos[0] = value; } 
     get { return Foos[0]; } 
    } 

    public string Foo2 
    { 
     set { Foos[1] = value; } 
     get { return Foos[1]; } 
    } 

    } 

然後你的類並沒有真正改變,因爲儘管它與所有其他代碼的合同,因爲屬性仍然存在,但現在您可以將權限分配給Foos,而不是通過每個單獨的屬性。

再一次,實際上如果我自己做,我實際上會使用DynamicMethod

1

就我個人而言,我不同意這裏的大多數其他海報。我認爲反射的使用應限於真正需要的情況(對象檢查,某些GUI情況等)。在這種情況下,只需多打一點,就可以編寫一個強類型的程序,並且仍然可以做你想做的事。我會提供兩種選擇。這兩種替代方法都可以通過名稱和索引訪問您的屬性。

在第一個替代方案中,我假設我們可以更改屬性的定義。在第二種選擇中,我會假定這些定義必須保持不變。

第一替代移動數據到一個單獨的陣列中,添加了輔助方法通過索引來訪問數據,並改變屬性以使用輔助方法:

private class Version1 { 
    private readonly string[] underlyingData=new string[50]; 

    public string Foo1 { get { return ReadFoo(1); } set { SetFoo(1, value); } } 
    public string Foo2 { get { return ReadFoo(2); } set { SetFoo(2, value); } } 
    public string Foo3 { get { return ReadFoo(3); } set { SetFoo(3, value); } } 
    //...... 
    public string Foo50 { get { return ReadFoo(50); } set { SetFoo(50, value); } } 

    private string ReadFoo(int index) { 
    return underlyingData[index-1]; //1-based indexing 
    } 

    private void SetFoo(int index, string value) { 
    underlyingData[index-1]=value; //1-based indexing 
    } 
} 

第二種選擇離開屬性定義不變,以及代表這些屬性的讀寫功能的兩個靜態代表數組。

private class Version2 { 
    private static readonly Func<Version2, string>[] readers=new Func<Version2, string>[] { 
    c => c.Foo1, 
    c => c.Foo2, 
    c => c.Foo3, 
    //...... 
    c => c.Foo50, 
    }; 

    private static readonly Action<Version2, string>[] writers=new Action<Version2, string>[] { 
    (c,v) => c.Foo1=v, 
    (c,v) => c.Foo2=v, 
    (c,v) => c.Foo3=v, 
    //...... 
    (c,v) => c.Foo50=v, 
    }; 

    public string Foo1 { set; get; } 
    public string Foo2 { set; get; } 
    public string Foo3 { set; get; } 
    //...... 
    public string Foo50 { set; get; } 

    private string ReadFoo(int index) { 
    return readers[index-1](this); //1-based indexing 
    } 

    private void SetFoo(int index, string value) { 
    writers[index-1](this, value); //1-based indexing 
    } 
}