代码之家  ›  专栏  ›  技术社区  ›  Dave

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

  •  0
  • Dave  · 技术社区  · 15 年前

    这是我在这方面最难回答的问题之一。:)虽然标题可能没有意义,但希望问题本身会有意义。

    假设我有一个像 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"]);
    ...
    

    但现在我决定不想这样做了。我想换我的 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”传递给我的扩展方法来实现这一点。我真正想传递的是一种类似于糖果的东西。

    这个问题可能有点混乱,所以总的来说,我接受两种答案中最好的一种:

    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 回复  |  直到 15 年前
        1
  •  1
  •   Jon Skeet    15 年前

    好吧,你可以用:

    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
          }
      }