Linq к DataSet - обрабатывающий нулевые значения

У меня есть требование для преобразования LINQ в DataTable.

Я украл следующий Дополнительный Метод у StackOverflow:

public static DataTable ToDataTable<T>(this IEnumerable<T> items)
        {
            var tb = new DataTable(typeof(T).Name);
            PropertyInfo[] props = 
            typeof(T).GetProperties(BindingFlags.Public
                                  | BindingFlags.Instance);

            foreach (var prop in props)
            {
                tb.Columns.Add(prop.Name, prop.PropertyType);
            }

            foreach (var item in items)
            {
                var values = new object[props.Length];
                for (var i = 0; i < props.Length; i++)
                {
                    values[i] = props[i].GetValue(item, null);
                }

                tb.Rows.Add(values);
            }
            return tb;
  } 

Когда таблица содержит нулевые значения, она выдает исключение. (т.е.)

DataSet does not support System.Nullable<> 

Comission (Десятичный тип) столбец содержит нулевое значение),

в

tb.Columns.Add(prop.Name, prop.PropertyType);

Как зафиксировать его?

5
задан Dhina 30 January 2010 в 19:38
поделиться

2 ответа

Это можно сделать с помощью команды дисплеев .

display/i $ pc разобрает текущую инструкцию непосредственно перед приглашением печатается каждый раз:

(gdb) b main
Breakpoint 1 at 0x80483b5: file hw.c, line 5.
(gdb) display/i $pc
(gdb) r
Starting program: /tmp/hw

Breakpoint 1, main () at hw.c:5
5         puts("Hello world");
1: x/i $pc
0x80483b5 <main+17>:    movl   $0x8048490,(%esp)

Теперь выполните инструкцию (затем просто продолжайте нажимать Enter, чтобы повторить):

(gdb) si
0x080483bc      5         puts("Hello world");
1: x/i $pc
0x80483bc <main+24>:    call   0x80482d4 <puts@plt>
(gdb) 
0x080482d4 in puts@plt ()
1: x/i $pc
0x80482d4 <puts@plt>:   jmp    *0x804959c
Current language:  auto; currently asm
(gdb) 
0x080482da in puts@plt ()
1: x/i $pc
0x80482da <puts@plt+6>: push   $0x10
(gdb) 
0x080482df in puts@plt ()
1: x/i $pc
0x80482df <puts@plt+11>:        jmp    0x80482a4 <_init+48>

Это все еще работает, когда мы доходим до этой точки:

(gdb) 
0x080482a4 in ?? ()
1: x/i $pc
0x80482a4 <_init+48>:   pushl  0x804958c
(gdb) 
0x080482aa in ?? ()
1: x/i $pc
0x80482aa <_init+54>:   jmp    *0x8049590
(gdb) 
0xb7f052d0 in _dl_runtime_resolve () from /lib/ld-linux.so.2
1: x/i $pc
0xb7f052d0 <_dl_runtime_resolve>:       push   %eax

Более одного выражения дисплеев может быть активным одновременно (используйте недисплеи < число > , чтобы удалить их). Например, чтобы посмотреть, что происходит с % eax :

(gdb) display/x $eax
2: /x $eax = 0xbf90ab34
(gdb) si
0xb7f052d1 in _dl_runtime_resolve () from /lib/ld-linux.so.2
2: /x $eax = 0xbf90ab34
1: x/i $pc
0xb7f052d1 <_dl_runtime_resolve+1>:     push   %ecx
(gdb) 
0xb7f052d2 in _dl_runtime_resolve () from /lib/ld-linux.so.2
2: /x $eax = 0xbf90ab34
1: x/i $pc
0xb7f052d2 <_dl_runtime_resolve+2>:     push   %edx
(gdb) 
0xb7f052d3 in _dl_runtime_resolve () from /lib/ld-linux.so.2
2: /x $eax = 0xbf90ab34
1: x/i $pc
0xb7f052d3 <_dl_runtime_resolve+3>:     mov    0x10(%esp),%edx
(gdb) 
0xb7f052d7 in _dl_runtime_resolve () from /lib/ld-linux.so.2
2: /x $eax = 0xbf90ab34
1: x/i $pc
0xb7f052d7 <_dl_runtime_resolve+7>:     mov    0xc(%esp),%eax

... и здесь изменение в % eax можно увидеть:

(gdb) 
0xb7f052db in _dl_runtime_resolve () from /lib/ld-linux.so.2
2: /x $eax = 0xb7f0d668
1: x/i $pc
0xb7f052db <_dl_runtime_resolve+11>:    call   0xb7eff780 <_dl_fixup>
(gdb) 
-121--4859617-

См. также: SO 327980 .

Комитет Standard C создал технический отчет TR 24731-1 , частично по инициативе Microsoft (я полагаю). Она стандартизирует интерфейсы для различных функций, таких как vsnprintf _ s () . Однако, к сожалению, интерфейс, определенный стандартом, несовместим с интерфейсом, определенным Microsoft, что делает стандарт в значительной степени неактуальным.

Например, TR 24731-1 говорит, что интерфейс для vsnprintf _ s () является:

#define _ _STDC_WANT_LIB_EXT1_ _ 1
#include <stdarg.h>
#include <stdio.h>
int vsnprintf_s(char * restrict s, rsize_t n,
                const char * restrict format, va_list arg);

К сожалению, MSDN говорит, что интерфейс для vsnprintf _ s () является:

int vsnprintf_s(
   char *buffer,
   size_t sizeOfBuffer,
   size_t count,
   const char *format,
   va_list argptr 
);

Буфер параметров

  • - Место хранения местоположение для вывода.
  • startOfBuffer - размер буфера для вывода.
  • count - максимальное количество записываемых символов (не включая завершающее значение null) или _TRUNCATE.
  • format - спецификация формата.
  • argptr - указатель на список аргументов.

Обратите внимание, что это не просто вопрос отображения типа: количество фиксированных аргументов различно и поэтому непримиримо. Для меня также неясно (и, предположительно, для комитета по стандартам тоже), какая польза есть от того, чтобы иметь и ', и' count '; он выглядит как одна и та же информация дважды (или, по крайней мере, код обычно записывается с одинаковым значением для обоих параметров).

-121--2881570-

Вот сутенерская версия:

public static DataTable ToDataTable<T>(this IEnumerable<T> items) { 
    DataTable table = new DataTable(typeof(T).Name);
    PropertyInfo[] props = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance); 

    foreach (var prop in props) {
        Type propType = prop.PropertyType;

        // Is it a nullable type? Get the underlying type
        if (propType.IsGenericType && propType.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
            propType = new NullableConverter(propType).UnderlyingType; 

        table.Columns.Add(prop.Name, propType);
    } 

    foreach (var item in items) { 
        var values = new object[props.Length]; 
        for (var i = 0; i < props.Length; i++)
            values[i] = props[i].GetValue(item, null);  

        table.Rows.Add(values); 
    }

    return table;
}

Edit : Немного изменил мой код, протестировал его, он работает!:)

5
ответ дан 14 December 2019 в 13:36
поделиться

Вы можете проверить наличие null, а затем вместо этого сохранить DBNull.Value в качестве значения. В MSDN есть статья о нулевых значениях , в которой особо подчеркивается отсутствие поддержки Nullable <> наборами данных.

Если у вас есть

values[i] = props[i].GetValue(item, null);

, сделайте это

var value = props[i].GetValue(item, null);
values[i] = value ?? ((object)DBNull.Value);
1
ответ дан 14 December 2019 в 13:36
поделиться
Другие вопросы по тегам:

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