我设置了如下属性:
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;}
那么我就像下面这样遍历一个集合:
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.
}
是否有简单的方法来做到这一点?
我认为更好的设计应该是:
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
中的值确定索引吗?
你可以在循环中使用反射:
for ( int i = 1 ; i < 51 ; i++)
this.GetType().GetProperty(string.Format("Foo{0}",i)).SetValue(this,desiredValue,null);
但是我想我会推荐使用索引器
http://msdn.microsoft.com/en-us/library/2549tw02%28v=vs.80%29.aspx你可以这样做:
- 使用for循环代替foreach。这样就可以使用当前索引进行操作。
- 使用反射。您可以获取类的属性列表并动态访问它们。例如:Type.GetProperties。
但是你为什么不直接使用一个List<string> Foos
而不是很多属性呢?
你应该使用反射。
this.GetType()。GetProperty("Foo" + i).SetValue(this, sortedCollection[element], null);
- GetProperty的开销不为空。如果你经常这样做,你可能想把GetProperty的结果存储在某个字段中然后在foreach中使用这个字段。
- 如果你的属性真的被命名为Something1, Something2,等等…,那么你可能有一个设计缺陷,你可能想在这样做之前纠正(用一个列表替换你所有的字符串成员)。
您需要使用反射(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);
}
}
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;
}
}
我实际上会使用反射,或者如果这被调用很多,做一个动态方法和ILEmit来做它(在运行时比反射快得多)。
然而,只是建议一些不同的东西,你可以改变包含Foo*属性的类,让每个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
就我个人而言,我不同意这里大多数其他海报。我认为反射的使用应该限制在那些真正需要它的情况下(对象检查,特定的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
}
}