Итерация по DataSet

Короткий ответ: «Это не очень хорошо».

Он вызывает f для каждого из args... и отбрасывает возвращаемое значение. Но это делает так, что в ряде случаев приводит к неожиданному поведению.

Код не имеет гарантий порядка, и если возвращаемое значение f для данного Arg имеет перегруженный operator, может иметь неприятные побочные эффекты.

С некоторым белым пространством:

[](...){}(
  (
    f(std::forward<Args>(args)), 0
  )...
);

Мы начнем изнутри.

f(std::forward<Args>(args)) - это неполное утверждение, которое можно разложить на .... Он будет вызывать f на одном из args при расширении. Вызовите это утверждение INVOKE_F.

(INVOKE_F, 0) принимает возвращаемое значение f(args), применяет operator,, затем 0. Если возвращаемое значение не имеет переопределений, это отбрасывает возвращаемое значение f(args) и возвращает значение 0. Назовите это INVOKE_F_0. Если f возвращает тип с переопределением operator,(int), здесь происходят плохие вещи, и если этот оператор возвращает не-POD-esque-тип, вы можете получить «условно поддерживаемое» поведение позже.

[](...){} создает лямбда, которая принимает вариации C-стиля как единственный аргумент. Это не то же самое, что пакеты параметров C ++ 11, или C ++ 14 variadic lambdas. Возможно, незаконно передавать не-POD-esque типы в функцию .... Вызвать это HELPER

HELPER(INVOKE_F_0...) - это расширение пакета параметров. в контексте вызова HELPER 's operator(), который является юридическим контекстом. Оценка аргументов не определена, и из-за подписи HELPER INVOKE_F_0..., вероятно, должны содержаться только простые старые данные (в языке C ++ 03), или, более конкретно, [expr.call] / p7 говорит: (через @ TC)

Передача потенциально оцененного аргумента типа класса (раздел 9), имеющего нетривиальный конструктор копирования, нетривиальный конструктор перемещения или нетривиальный деструктор без соответствующего параметра, условно поддерживается семантикой, определяемой реализацией.

Таким образом, проблемы этого кода заключаются в том, что порядок не задан и , он полагается на варианты выбора подходящего варианта компилятора или .

Мы можем исправить проблему operator, следующим образом:

template <class F, class... Args> 
void for_each_argument(F f, Args&&... args) { 
  [](...){}((void(f(std::forward<Args>(args))), 0)...); 
}

, тогда мы можем гарантировать порядок, разложив в инициализаторе:

template <class F, class... Args> 
void for_each_argument(F f, Args&&... args) { 
  int unused[] = {(void(f(std::forward<Args>(args))), 0)...}; 
  void(unused); // suppresses warnings
}

, но приведенное выше не выполняется, когда Args... пуст, поэтому добавьте еще 0:

template <class F, class... Args> 
void for_each_argument(F f, Args&&... args) { 
  int unused[] = {0, (void(f(std::forward<Args>(args))), 0)...}; 
  void(unused); // suppresses warnings
}

, и нет никакой веской причины для компилятора НЕ удалять unused[] из existance, а еще оценивать f в args... по порядку.

Моим предпочтительным вариантом является:

template <class...F>
void do_in_order(F&&... f) { 
  int unused[] = {0, (void(std::forward<F>(f)()), 0)...}; 
  void(unused); // suppresses warnings
}

, который принимает нулевую лямбда и запускает их по одному, слева направо. (Если компилятор может доказать, что порядок не имеет значения, он может свободно вывести их из строя).

Затем мы можем реализовать выше:

template <class F, class... Args> 
void for_each_argument(F f, Args&&... args) { 
  do_in_order( [&]{ f(std::forward<Args>(args)); }... );
}

, который помещает «странное расширение» в изолированную функцию (do_in_order), и мы можем использовать его в другом месте. Мы также можем написать do_in_any_order, который работает аналогичным образом, но делает any_order понятным: однако, исключая экстремальные причины, код, выполняемый в предсказуемом порядке в расширении пакета параметров, уменьшает неожиданность и уменьшает головные боли до минимума.

Недостатком метода do_in_order является то, что не все компиляторы, подобные ему, - расширение пакета параметров, содержащего инструкцию, содержащую целые подзапросы, не является тем, что они ожидают сделать.

29
задан Steven Doggart 13 February 2015 в 12:01
поделиться

2 ответа

Просто петля ...

foreach(var table in DataSet1.Tables) {
    foreach(var col in table.Columns) {
       ...
    }
    foreach(var row in table.Rows) {
        object[] values = row.ItemArray;
        ...
    }
}
15
ответ дан Marc Gravell 13 February 2015 в 12:01
поделиться
foreach (DataTable table in dataSet.Tables)
{
    foreach (DataRow row in table.Rows)
    {
        foreach (object item in row.ItemArray)
        {
            // read item
        }
    }
}

Или, если вам нужна информация о столбце:

foreach (DataTable table in dataSet.Tables)
{
    foreach (DataRow row in table.Rows)
    {
        foreach (DataColumn column in table.Columns)
        {
            object item = row[column];
            // read column and item
        }
    }
}
87
ответ дан Community 13 February 2015 в 12:01
поделиться
Другие вопросы по тегам:

Похожие вопросы: