2010-11-20 74 views
0

这是我在这里讨论过的最难的问题之一。 :)虽然标题可能没有意义,但希望问题本身会。在传递函数之前转换数据的简单方法?

比方说,我有这样一个Dictionary<string, List<double>>的数据结构,和我有函数,然后采取List<double> S作为参数:

Dictionary<string, List<double>> candy_positions = new Dictionary<string, List<double>>(); 
candy_positions.Add("Godiva", new List<double> { 1.0, 2.0, 4.0 }); 
EatCandy(candy_positions["Godiva"]); 
... 

但现在我已经决定,我并不想这样做这条路。我想用一个List<CandyPositions>,其中CandyPositions看起来像这样来代替我的Dictionary

public class CandyPositions 
{ 
    public double Sees; 
    public double Godiva; 
    public double Lindt; 
} 

可是,我真的想()独自离开EatCandy。显然,现在的问题是我的数据不适合直接传递给方法。相反,我必须做喜欢的事,瘸子:

List<CandyPositions> candy_positions = new List<CandyPositions>(); 
... 
var positions = from x in candy_positions select x.Godiva; 
EatCandy(positions.ToList()); 

一次我要调用的方法。我宁愿是能够做到这一点更简单的方法,如:

EatCandy(candy_positions.GetPositionsFor("Godiva")); 

其中参数“戈黛娃”在CandyPositions类属性名相匹配。

写完这个问题后,我意识到它并不是真的关于转置数据 - 它的一部分可以通过编写扩展方法来处理。我不知道该怎么做的部分是传入一个属性名称,以便扩展方法可以将其与一个类的属性相关联。我不想传入字符串,主要是因为这会打开各种运行时错误的大门。我知道如何通过将“Godiva”传递给我的扩展方法来完成这项工作。我真正想传入的内容与CandyPositions.Godiva类似。

这个问题可能是有点混乱,因此,在总结,我会接受最好的两种答案的:

  1. 有没有更好的方式来处理移调数据,而不是使用扩展方法+某种方式访问​​属性名称?
  2. 有没有办法指定我希望我的扩展方法检索的属性,而不是字符串?

我目前的扩展方法是这样的:

public static List<double> GetPositions(this List<CandyPositions> positions, string candy_name) 
{ 
    return (from x in positions select x.GetType().GetProperty(candy_name).GetValue(x, null)).Cast<double>().ToList(); 
} 

回答

1

嗯,你可以使用:

public static List<double> GetPositions(this List<CandyPositions> positions, 
             Func<CandyPositions, double> projection) 
{ 
    return positions.Select(projection).ToList(); 
} 

,并称之为:

EatCandy(candyPositions.GetPositions(x => x.Godiva)); 

在另一方面,如果您可以将EatCandy更改为接受IEnumerable<double>相反,你不需要额外的方法 - 你可以用:

EatCandy(candyPositions.Select(x => x.Godiva)); 

,而完全不写一个额外的方法。

编辑:如果你需要一次遍历两个序列,有两种选择:

  • 如果您使用.NET 4,你可以使用Zip扩展方法。
  • 否则,你基本上可以写你自己:

    using (var iterator1 = sequence1.GetEnumerator()) 
    using (var iterator2 = sequence2.GetEnumerator()) 
    { 
        while (iterator1.MoveNext() && iterator2.MoveNext()) 
        { 
         var value1 = iterator1.Current; 
         var value2 = iterator2.Current; 
         // Use the values here 
        } 
    } 
    
+0

哇,甚至都没有发生,我认为非常酷的做法。谢谢,乔恩!还有一个脱离主题的评论 - 我很高兴我的新C#书的订单将于下周发布。 :) – Dave 2010-11-20 08:09:01

+0

在我的特殊情况下,我不能使用IEnumerable ,因为我只需要通过索引访问数据,因为我有两个列表,以及一个类似'a [i] .foo(b [i] )'。我一直认为这是做这件事的方式,但如果你知道一些很酷的方法可以让我使用foreach并保持'a'和'b'同步,请告诉我! :) – Dave 2010-11-20 08:18:45

+0

@Dave:绝对有这样做的方法。将编辑。很高兴听到你有这本书的方式 - 希望你喜欢它!有疑问, – 2010-11-20 17:20:36