在传递给函数之前转换数据的简单方法?

时间:2010-11-20 07:22:12

标签: c# reflection .net-3.5 properties

这是我在SO上所遇到的最困难的问题之一。 :)虽然标题可能没有意义,但希望这个问题本身会有。

假设我有一个像Dictionary<string, List<double>>这样的数据结构,并且我有函数,然后将List<double>作为参数:

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"]);
...

但是现在我已经决定我不想这样做。我想将Dictionary替换为List<CandyPositions>,其中CandyPositions看起来像这样:

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"));

其中参数“Godiva”与CandyPositions类中的属性名称匹配。

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

这个问题可能有点令人困惑,总而言之,我会接受以下两种答案中的最佳答案:

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

    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 个答案:

答案 0 :(得分: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
        }
    }