2015-11-04 1 views
0

Я хотел написать общий код, который возвращает результаты процедуры Sql Server как объекты DataTable. Затем я написал код ниже, но я наткнулся на проблему DataTable.Rows.Add(), ожидающую параметр params object [], в то время как я должен пройти IEnumerable.Есть ли способ обработать IEnumerable <T> как объект params T []?

public static DataTable GetProcedureResults(int id) 
    { 
     return GetQueryResultAsDataTable<MyProcedure_Result>(_sqlServerDB.MyProcedure(id)); 
    } 

    private static DataTable GetQueryResultAsDataTable<T>(ObjectResult<T> objectResult) 
    { 
     DataTable resultAsDataTable = new DataTable("Result"); 
     var columns = typeof(T).GetProperties(); 
     foreach (var column in columns) 
     { 
      resultAsDataTable.Columns.Add(column.Name, typeof(string)); 
     } 

     foreach (var resultRecord in objectResult) 
     { 
      var fields = resultRecord.GetType().GetProperties().Select(p => p.GetValue(resultRecord).ToString()); 
      resultAsDataTable.Rows.Add(fields); 
     } 

     return resultAsDataTable; 
    } 

Для тех, кто знаком с этим вопросом, вы уже догадались, что мой DataTable в конце выглядит следующим образом:

enter image description here

Значения трактуются как единый объект, таким образом, все вставляются в 1-й столбец.

Какое обходное решение здесь, если оно есть? Я читал в других сообщениях, которые, кажется, C# 6 будет исправить этот вопрос, кроме этого, не нашел четкого и краткого решения.

+0

Может вы не просто 'resultAsDataTable.Rows.Add (fields.ToArray());'? –

+0

@DavidL: Разъяснение: Я хотел «сгладить» IEnumerable так, чтобы он превратился в объект params T [], и, следовательно, datatable заселен правильно. Пример: если мой IEnumerable является списком {1, 4, 5, 6} Я бы хотел, чтобы он обрабатывался как datatable.Rows.Add (1, 4, 5, 6); – Veverke

+0

Разрешая передавать IEnumerable для params args, было только предложение для C# 6; но он не попал в финальный выпуск. – Sehnsucht

ответ

4

Если у вас есть IEnumerable<T>, и метод ожидает T[], просто позвоните ToArray по вашему перечислимому.

var fields = resultRecord.GetType().GetProperties().Select(p => p.GetValue(resultRecord).ToString()); 
resultAsDataTable.Rows.Add(fields.ToArray()); 

Способность определять params параметры IEnumerable<T>, а не T[] не в конечном итоге сделать это в C# 6 (см Eric Lippert's answer about the feature, который связывается с объявлением функции удаления из C# 6). Однако даже с этой теоретической особенностью в этом случае это не помогло бы. Эта функция позволила бы разработчику API (например, человеку, пишущему DataRowCollection.Add) принять IEnumerable<T>, а не T[], если они этого захотят (в этом случае они почти наверняка не будут, так как это будет молчаливое изменение). Это не позволяет вам передать IEnumerable<T> методу, ожидающему T[]. Как вызывающий метод, если вы не используете атрибут params этого параметра (то есть передаете отдельные аргументы, а не коллекцию), тогда это просто «нормальный» метод, который принимает массив, и вы отвечаете за преобразование вашего аргумента в ожидаемый тип.

+0

Ничего себе, это просто? что я делал ... это делает это. Благодаря! – Veverke

+0

Позвольте мне понять: какая разница в том, что компилятор получает IEnumerable или массив?! Почему он способен сгладить последовательность только в том случае, если это массив, а не когда он является IEnumerable? У меня создалось впечатление, что проблема заключалась в том, что компилятор не смог * сгладить * последовательность IEnumerable и сделать ее как e1, e2, e3, e4 - это то, что должен выглядеть объект params object []. Почему это ограниченно для массива, но не для IEnumerable? – Veverke

+0

разница; IEnumerable не является массивом; поэтому, ожидая массив, который IEnumerable не будет соответствовать (другой способ работает, хотя, поскольку массив IS является IEnumerable).Как то, что является IEnumerable, просто укажите, что это объект, который будет давать (позже) значения при перечислении, он не содержит значений напрямую; он знает, как их подавать по запросу (например, через foreach). Не поняла, что касается уплощения, сглаживание - это больше, когда у вас есть контейнер с контейнерами, и вы хотите иметь один контейнер со всеми значениями контейнеров, каким-то образом конкретизированными. – Sehnsucht

1

Вы можете фактически передать массив в params object[], поэтому временное решение может быть просто:

var fields = resultRecord.GetType().GetProperties() 
            .Select(p => p.GetValue(resultRecord).ToString()) 
            .ToArray(); 
resultAsDataTable.Rows.Add(fields); 
+0

Да, это делает то же самое решение, предлагаемое * bdukes *. – Veverke

Смежные вопросы