Простой способ транспонировать данные перед передачей в функции? - PullRequest
0 голосов
/ 20 ноября 2010

Это один из самых сложных вопросов, которые мне приходилось задавать здесь, на SO. :) Хотя название может не иметь смысла, надеюсь, сам вопрос подойдет.

Допустим, у меня есть структура данных, подобная 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.

После написания этого вопроса я понял, что речь не идет о транспонировании данных - эту часть можно обработать, написав метод расширения. Часть, которую я не знаю, как сделать, это передать имя свойства, чтобы метод расширения мог взять это и связать его со свойством класса. Я также не хочу передавать строку, главным образом потому, что это откроет дверь для всех видов ошибок во время выполнения. Я знаю, как сделать эту работу, передав «Годиву» моему методу расширения. То, что я действительно хочу передать, - это что-то вроде 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 Ответ

1 голос
/ 20 ноября 2010

Ну, вы можете использовать:

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