如何将可变长度列表映射到对象属性?

问题描述:

在这种情况下我有一个包含与此命名约定一些字符串属性的对象FooFoo.Bar1Foo.Bar2,等...如何将可变长度列表映射到对象属性?

我想用未知长度的字符串列表来映射到每个Bar( N)属性:

public class Mapper() 
{  
    public Foo MapToFoo(List<string> list) 
    { 
    var Foo = new Foo(); 
    foreach (var item in list) 
    { 
     //? Here is some psudo-code/logic of what I am trying to achieve: 
     //Bar*X* = item 
     //X++ 
    } 
    return Foo; 
    } 
} 

public class Foo 
{ 
    public string Bar1 { get; set; } 
    public string Bar2 { get; set; } 
    public string Bar3 { get; set; } 
} 

我承认我可以只添加public List<string> Bars和摆脱Bar1Bar2Bar3。虽然这可能是首选的解决方案,但在我的特殊情况下,需要对紧密结合的传统项目进行大量更改。

有没有办法做到这一点?如果是这样,那么映射永远不会寻找不存在的BarX(即在这种情况下为Bar4)?

+0

这是可能的,你将有你有许多悬而未决的要求,才能使用云南财贸为 –

+1

。如果列表的字符串多于Foo的属性,该怎么办?如果有更多的Foo属性比字符串?反射的属性不保证顺序,字符串2可以设置Bar3值吗?我建议你不要这样做,建立一个[Adapter](https://en.wikipedia.org/wiki/Adapter_pattern)来桥接遗留代码。 – Crowcoder

既然你不能使用像Bars任何东西,你可能需要使用反射,这样的事情:

public class Mapper 
{ 
    public Foo MapToFoo(List<string> list) 
    { 
     var Foo = new Foo(); 
     var props = typeof(Foo).GetProperties() 
           .Where(pi => pi.Name.StartsWith("Bar")) 
           .OrderBy(pi => pi.Name).ToList(); 

     for (int i = 0; i < Math.Min(list.Count, props.Count); i++) 
      props[i].SetValue(Foo, list[i]); 

     return Foo; 
    } 
} 

但也许使用属性名称的Dictionary<string, string>和值更适合:

var mapper = new Mapper(); 

var values = new Dictionary<string, String>(); 
values["Bar1"] = "A"; 
values["Bar2"] = "B"; 
values["Bar3"] = "C"; 

var foo = mapper.MapToFoo(values); 

... 
public class Mapper 
{ 
    public Foo MapToFoo(Dictionary<string, string> values) 
    { 
     var Foo = new Foo(); 
     foreach (var item in values) 
     { 
      var prop = typeof(Foo).GetProperty(item.Key); 

      if (prop != null) 
       prop.SetValue(Foo, item.Value); 
     } 

     return Foo; 
    } 
} 

您可以使用反射来实现相同。假设你的属性被命名为Bar1,Bar2,Bar3 ...等等,你可以执行以下操作。

public Foo MapToFoo(List<string> list) 
    { 
     var Foo = new Foo(); 
     var propertyName = "Bar"; 
     int index = 1; 
     foreach (var item in list) 
     { 
      var property = Foo.GetType().GetProperty(string.Format("{0}{1}", propertyName, index)); 
      if(property != null) 
      { 
       property.SetValue(Foo, item); 
      } 
      index++; 
     } 
     return Foo; 
    } 

我的意思是,你可以使用反射得到所有的属性:

PropertyInfo[] properties = type.GetProperties(); 

foreach (PropertyInfo property in properties) 
{ 
    //Store the values in an sort them 
} 

但这保证顺序,这样你将不得不对它们进行排序。

只因为你可以,并不意味着你应该。你应该问自己:“我为什么要这样做?”和“是否有更简单/更易维护的解决方案?”

您可以使用反射:

public class Mapper() 
{  
    public Foo MapToFoo(List<string> list) 
    { 
     Foo f = new Foo(); 
     var bars = f.GetType().GetProperties(); 
     int i=0; 
     foreach (var item in list) 
     { 
      bars[i++].SetValue(f, item); 
      if(i==bars.Length) 
       break; 
     } 
     return f; 
    } 
} 

public class Foo 
{ 
    public string Bar1 { get; set; } 
    public string Bar2 { get; set; } 
    public string Bar3 { get; set; } 
}