Jenerik List / Enumerable DataTable dönüştürmek?


261

Farklı Genel Listeleri döndüren birkaç yöntem var.

.Net herhangi bir sınıf statik yöntem veya herhangi bir liste veri tablosuna dönüştürmek için ne var? Hayal edebileceğim tek şey bunu yapmak için Yansıma kullanmaktır.

Eğer bu varsa:

List<Whatever> whatever = new List<Whatever>();

(Bu sonraki kod elbette çalışmıyor, ama ben olasılığı var:

DataTable dt = (DataTable) whatever;

2
Elbette, iyi bir soru "neden?" - Liste <T> çoğu durumda DataTable'dan daha iyi bir araç olduğunda; - p Her biri kendi başına, sanırım ...
Marc Gravell

1
Bunun bu sorunun bir kopyası olabileceğini düşünüyorum: stackoverflow.com/questions/523153/… Hatta neredeyse aynı bir cevabı var. :-)
mezoid

2
@MarcGravell: Benim "neden?" Liste <T> manipülasyonudur (Çapraz sütunlar ve satırlar). List <T> bir pivot yapmaya çalışıyorum ve yansıma yoluyla özelliklere erişmek bir acı. Yanlış mı yapıyorum?
Eduardo Molteni

1
@Eduardo, orada yansıma ağrısını gidermek için çok sayıda araç var - FastMember akla geliyor. Bu olabilir hepsi bağlamda bağlıdır - ayrıca bir DataTable belirli senaryolar için yararlı olduğunu olabilir. Belki de en büyük sorun, tüm veri depolama için DataTable kullanarak kişidir o var diye seçeneklerini ve bunların senaryoyu dikkate almak zaman almadan,.
Marc Gravell

@EduardoMolteni ilgileniyorsanız, FastMember'i bunun için doğrudan destek alacak şekilde güncelledim
Marc Gravell

Yanıtlar:


325

İşte NuGet'ten FastMember kullanarak 2013 güzel bir güncelleme :

IEnumerable<SomeType> data = ...
DataTable table = new DataTable();
using(var reader = ObjectReader.Create(data)) {
    table.Load(reader);
}

Maksimum performans için FastMember'in meta programlama API'sini kullanır. Belirli üyelerle sınırlandırmak (veya siparişi zorlamak) istiyorsanız, bunu da yapabilirsiniz:

IEnumerable<SomeType> data = ...
DataTable table = new DataTable();
using(var reader = ObjectReader.Create(data, "Id", "Name", "Description")) {
    table.Load(reader);
}

Editörün Dis / Hak Talebi : FastMember bir Marc Gravell projesidir. Altın ve tam sinek!


Evet, bu hemen hemen tam tersidir bu one; yansıma yeterli olacaktır - ya da daha hızlı, HyperDescriptor2.0'da ya da belki 3.5'te ihtiyacınız varsa Expression. Aslında, HyperDescriptorfazlasıyla yeterli olmalıdır.

Örneğin:

// remove "this" if not on C# 3.0 / .NET 3.5
public static DataTable ToDataTable<T>(this IList<T> data)
{
    PropertyDescriptorCollection props =
        TypeDescriptor.GetProperties(typeof(T));
    DataTable table = new DataTable();
    for(int i = 0 ; i < props.Count ; i++)
    {
        PropertyDescriptor prop = props[i];
        table.Columns.Add(prop.Name, prop.PropertyType);
    }
    object[] values = new object[props.Count];
    foreach (T item in data)
    {
        for (int i = 0; i < values.Length; i++)
        {
            values[i] = props[i].GetValue(item);
        }
        table.Rows.Add(values);
    }
    return table;        
}

Şimdi tek bir çizgi ile bunu yansımadan çok daha hızlı yapabilirsiniz ( HyperDescriptornesne tipini etkinleştirerek T).


düzenlemek re performance query; İşte sonuçları olan bir test aracı:

Vanilla 27179
Hyper   6997

Darboğazın üye erişiminden DataTableperformansa değiştiğinden şüpheleniyorum ... Şüpheliyim ki bu konuda çok şey geliştireceksiniz ...

kod:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
public class MyData
{
    public int A { get; set; }
    public string B { get; set; }
    public DateTime C { get; set; }
    public decimal D { get; set; }
    public string E { get; set; }
    public int F { get; set; }
}

static class Program
{
    static void RunTest(List<MyData> data, string caption)
    {
        GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
        GC.WaitForPendingFinalizers();
        GC.WaitForFullGCComplete();
        Stopwatch watch = Stopwatch.StartNew();
        for (int i = 0; i < 500; i++)
        {
            data.ToDataTable();
        }
        watch.Stop();
        Console.WriteLine(caption + "\t" + watch.ElapsedMilliseconds);
    }
    static void Main()
    {
        List<MyData> foos = new List<MyData>();
        for (int i = 0 ; i < 5000 ; i++ ){
            foos.Add(new MyData
            { // just gibberish...
                A = i,
                B = i.ToString(),
                C = DateTime.Now.AddSeconds(i),
                D = i,
                E = "hello",
                F = i * 2
            });
        }
        RunTest(foos, "Vanilla");
        Hyper.ComponentModel.HyperTypeDescriptionProvider.Add(
            typeof(MyData));
        RunTest(foos, "Hyper");
        Console.ReadLine(); // return to exit        
    }
}

4
"Olduğu gibi", yansıma kadar hızlı olacaktır. HyperDescriptor'ı etkinleştirirseniz, yansıma ellerini aşağı indirir ... Hızlı bir test yapacağım ... (2 dakika)
Marc Gravell

3.5 için ifade edildi. Kullanılırsa kodu nasıl etkiler, herhangi bir örnek var mı?
MicMit

3
@MarcGravell Evet İfade çözümüyle çok ilgilenirim. Hızlı + öğrenme etkisine ihtiyaç duyduğunuz için. Teşekkürler Marc!
Elisabeth

11
Ben çalışıyorum @Ellesedil açıkça böyle şeyler ifşa etmek hatırlamak, ama değilim çünkü satan bir şey (daha ziyade serbestçe kullanılabilir işin uzun saatler yapıyorum) Ben çok büyük miktarlarda hissetmiyorum itiraf suçluluk burada ...
Marc Gravell

2
ToDataTable yönteminiz null olabilecek alanları desteklemiyor: Ek bilgiler: DataSet, System.Nullable <> özelliğini desteklemiyor.
Dainius Kreivys

235

Null olabilecek türleri ve null değerleri işlemek için Marc Gravell'in örnek kodunu değiştirmek zorunda kaldım. Aşağıya çalışan bir sürüm ekledim. Teşekkürler Marc.

public static DataTable ToDataTable<T>(this IList<T> data)
{
    PropertyDescriptorCollection properties = 
        TypeDescriptor.GetProperties(typeof(T));
    DataTable table = new DataTable();
    foreach (PropertyDescriptor prop in properties)
        table.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType);
    foreach (T item in data)
    {
        DataRow row = table.NewRow();
        foreach (PropertyDescriptor prop in properties)
             row[prop.Name] = prop.GetValue(item) ?? DBNull.Value;
        table.Rows.Add(row);
    }
    return table;
}

Bu mükemmel bir cevap. Ben bir öğe özelliği içeren ve sütunlar aynı şekilde oluşturulan sütunlar listeye işlemek için genişletilmiş bu örnek görmek isterim.
Bilinmeyen Kodlayıcı

2
Bunu @Jim Beam elde etmek için, GroupBy dönüşünü kabul etmek için yöntem imzasını değiştirin: public static DataTable ToDataTable<TKey, T>(this IEnumerable<IGrouping<TKey, T>> data) Sonra, foreach döngüsünden önce fazladan bir sütun table.Columns.Add("Key", Nullable.GetUnderlyingType(typeof(TKey)) ?? typeof(TKey)); ekleyin : Ve sonra veri döngüsüne grupları yinelemek için bir döngü ekleyin: foreach (IGrouping <TKey, T> veri grubu) {foreach (gruptaki T öğesi. Öğeler) {Tüm ayrıntılar için bu GIST'e
Rick Dailey

hey, bir nesneyi iç nesnelerle işlemenin bir yolu var mı? Ben sadece iç Özellikler üst nesnenin sütunları sonra sütun olarak görünmesini istiyorum
heyNow

@heyNow, olduğundan eminim. Ama yaptığım şeyle bu işlevselliğe gerçekten ihtiyacım yoktu ve bu yüzden başka birinin genişletmesi için bıraktım. :)
Mary Hamlin

1
Bu eski bir gönderi, bu yorumun ne kadar yararlı olduğundan emin değilim, ancak bu ToDataTableyöntemde sinsi bir hata var . Bir Tarabirim uygularsa typeof(T), nesnenin gerçek sınıfı yerine arabirim türünü döndürebilir ve bu da boşluğa neden olabilir DataTable. Değiştirilmesi data.First().GetType()düzeltilmelidir.
Lucas

14

Veri tablosuna benzer değer türleriyle çalışmasını sağlamak için Marc'ın cevabında küçük bir değişiklik List<string>:

public static DataTable ListToDataTable<T>(IList<T> data)
{
    DataTable table = new DataTable();

    //special handling for value types and string
    if (typeof(T).IsValueType || typeof(T).Equals(typeof(string)))
    {

        DataColumn dc = new DataColumn("Value");
        table.Columns.Add(dc);
        foreach (T item in data)
        {
            DataRow dr = table.NewRow();
            dr[0] = item;
            table.Rows.Add(dr);
        }
    }
    else
    {
        PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(typeof(T));
        foreach (PropertyDescriptor prop in properties)
        {
            table.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType);
        }
        foreach (T item in data)
        {
            DataRow row = table.NewRow();
            foreach (PropertyDescriptor prop in properties)
            {
                try
                {
                    row[prop.Name] = prop.GetValue(item) ?? DBNull.Value;
                }
                catch (Exception ex)
                {
                    row[prop.Name] = DBNull.Value;
                }
            }
            table.Rows.Add(row);
        }
    }
    return table;
}

<int> Listesi için nasıl yapılır?
Muflix

1
Yukarıdaki yöntem int (ve diğer değer türleri) için de çalışacaktır ... int bir değer türüdür. bkz: msdn.microsoft.com/en-us/library/s1ax56ch.aspx
Onur Omer

Bunu bir uzantı yöntemi kullanmaya bağlı olmadığı için seviyorum. Uzantı Yöntemlerine erişimi olmayan eski kod tabanları için iyi çalışır.
webworm

13

Bu, çözümlerin basit bir karışımıdır. Null olabilecek türlerle çalışır.

public static DataTable ToDataTable<T>(this IList<T> list)
{
  PropertyDescriptorCollection props = TypeDescriptor.GetProperties(typeof(T));
  DataTable table = new DataTable();
  for (int i = 0; i < props.Count; i++)
  {
    PropertyDescriptor prop = props[i];
    table.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType);
  }
  object[] values = new object[props.Count];
  foreach (T item in list)
  {
    for (int i = 0; i < values.Length; i++)
      values[i] = props[i].GetValue(item) ?? DBNull.Value;
    table.Rows.Add(values);
  }
  return table;
}

Bu çözüm hataya meyillidir çünkü T sınıfındaki özellik bildirim sırasına bağlıdır.
Vahid Ghadiri

10

MSDN'deki bu bağlantı görülmeye değer: Nasıl yapılır: Genel T Türü DataRow Değil Burada CopyToDataTable <T> Uygulayın

Bu, bunu yapmanızı sağlayan bir uzantı yöntemi ekler:

// Create a sequence. 
Item[] items = new Item[] 
{ new Book{Id = 1, Price = 13.50, Genre = "Comedy", Author = "Gustavo Achong"}, 
  new Book{Id = 2, Price = 8.50, Genre = "Drama", Author = "Jessie Zeng"},
  new Movie{Id = 1, Price = 22.99, Genre = "Comedy", Director = "Marissa Barnes"},
  new Movie{Id = 1, Price = 13.40, Genre = "Action", Director = "Emmanuel Fernandez"}};

// Query for items with price greater than 9.99.
var query = from i in items
             where i.Price > 9.99
             orderby i.Price
             select i;

// Load the query results into new DataTable.
DataTable table = query.CopyToDataTable();

@PaulWilliams Teşekkürler, yıllardır bu kodu sorunsuz bir şekilde kullanıyorum. Ancak örnek kodu microsoft'tan kopyalamadığım ve yalnızca web sitesine bağlı olduğum için, diğer çözümler en azından en iyi uygulamalarla en iyi şekilde uyumludur stackoverflow.com/help/how-to-answer
Jürgen Steinblock

8

Başka bir yaklaşım yukarıdaki gibidir:

  List<WhateEver> lst = getdata();
  string json = Newtonsoft.Json.JsonConvert.SerializeObject(lst);
  DataTable pDt = JsonConvert.DeserializeObject<DataTable>(json);

Çok çok iyi ... ama 'System.OutOfMemoryException' türü istisnası attı. 500 000 ürünle kullandım ... Ama bunun için teşekkürler.
st_stefanov

Bu nette bulduğum en temiz çözüm. Harika iş!
Sarah

7
public DataTable ConvertToDataTable<T>(IList<T> data)
{
    PropertyDescriptorCollection properties =
        TypeDescriptor.GetProperties(typeof(T));

    DataTable table = new DataTable();

    foreach (PropertyDescriptor prop in properties)
            table.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType);

    foreach (T item in data)
    {
        DataRow row = table.NewRow();
        foreach (PropertyDescriptor prop in properties)
        {
           row[prop.Name] = prop.GetValue(item) ?? DBNull.Value;
        }
        table.Rows.Add(row);
    }
    return table;
}

3
Bu kod soruyu cevaplayabilirken, bu kodun soruyu neden ve / veya nasıl cevapladığı konusunda ek bağlam sağlamak uzun vadeli değerini arttırır.
kayess

Bu çözüm hataya meyillidir çünkü T sınıfındaki özellik bildirim sırasına bağlıdır.
Vahid Ghadiri

6

Marc Gravell'in cevabı ama VB.NET'te

Public Shared Function ToDataTable(Of T)(data As IList(Of T)) As DataTable
    Dim props As PropertyDescriptorCollection = TypeDescriptor.GetProperties(GetType(T))
    Dim table As New DataTable()
    For i As Integer = 0 To props.Count - 1
            Dim prop As PropertyDescriptor = props(i)
            table.Columns.Add(prop.Name, prop.PropertyType)
    Next
    Dim values As Object() = New Object(props.Count - 1) {}
    For Each item As T In data
            For i As Integer = 0 To values.Length - 1
                    values(i) = props(i).GetValue(item)
            Next
            table.Rows.Add(values)
    Next
    Return table
End Function

6

bunu dene

public static DataTable ListToDataTable<T>(IList<T> lst)
{

    currentDT = CreateTable<T>();

    Type entType = typeof(T);

    PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(entType);
    foreach (T item in lst)
    {
        DataRow row = currentDT.NewRow();
        foreach (PropertyDescriptor prop in properties)
        {

            if (prop.PropertyType == typeof(Nullable<decimal>) || prop.PropertyType == typeof(Nullable<int>) || prop.PropertyType == typeof(Nullable<Int64>))
            {
                if (prop.GetValue(item) == null)
                    row[prop.Name] = 0;
                else
                    row[prop.Name] = prop.GetValue(item);
            }
            else
                row[prop.Name] = prop.GetValue(item);                    

        }
        currentDT.Rows.Add(row);
    }

    return currentDT;
}

public static DataTable CreateTable<T>()
{
    Type entType = typeof(T);
    DataTable tbl = new DataTable(DTName);
    PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(entType);
    foreach (PropertyDescriptor prop in properties)
    {
        if (prop.PropertyType == typeof(Nullable<decimal>))
             tbl.Columns.Add(prop.Name, typeof(decimal));
        else if (prop.PropertyType == typeof(Nullable<int>))
            tbl.Columns.Add(prop.Name, typeof(int));
        else if (prop.PropertyType == typeof(Nullable<Int64>))
            tbl.Columns.Add(prop.Name, typeof(Int64));
        else
             tbl.Columns.Add(prop.Name, prop.PropertyType);
    }
    return tbl;
}

6
It's also possible through XmlSerialization.
The idea is - serialize to `XML` and then `readXml` method of `DataSet`.

I use this code (from an answer in SO, forgot where)

        public static string SerializeXml<T>(T value) where T : class
    {
        if (value == null)
        {
            return null;
        }

        XmlSerializer serializer = new XmlSerializer(typeof(T));

        XmlWriterSettings settings = new XmlWriterSettings();

        settings.Encoding = new UnicodeEncoding(false, false);
        settings.Indent = false;
        settings.OmitXmlDeclaration = false;
        // no BOM in a .NET string

        using (StringWriter textWriter = new StringWriter())
        {
            using (XmlWriter xmlWriter = XmlWriter.Create(textWriter, settings))
            {
               serializer.Serialize(xmlWriter, value);
            }
            return textWriter.ToString();
        }
    }

so then it's as simple as:

            string xmlString = Utility.SerializeXml(trans.InnerList);

        DataSet ds = new DataSet("New_DataSet");
        using (XmlReader reader = XmlReader.Create(new StringReader(xmlString)))
        { 
            ds.Locale = System.Threading.Thread.CurrentThread.CurrentCulture;
            ds.ReadXml(reader); 
        }

Not sure how it stands against all the other answers to this post, but it's also a possibility.

5

Bu görevi yerine getirmek için kendim küçük bir kütüphane yazdım. Yansımayı yalnızca bir nesne türünün veri tablosuna çevrileceği ilk kez kullanır. Bir nesne türünü çevirerek tüm işi yapacak bir yöntem yayar.

Çarpıcı hızlı. Burada bulabilirsiniz: GoogleCode üzerinde ModelShredder


2

Burada listelenen seçeneklerin hiçbiri benim durumumda işe yaramadığı için alternatif bir çözüm bulmak zorundaydım. Bir IEnumerable döndürdü bir IEnumerable kullanıyordum ve özellikleri numaralandırılamadı. Bu hile yaptı:

// remove "this" if not on C# 3.0 / .NET 3.5
public static DataTable ConvertToDataTable<T>(this IEnumerable<T> data)
{
    List<IDataRecord> list = data.Cast<IDataRecord>().ToList();

    PropertyDescriptorCollection props = null;
    DataTable table = new DataTable();
    if (list != null && list.Count > 0)
    {
        props = TypeDescriptor.GetProperties(list[0]);
        for (int i = 0; i < props.Count; i++)
        {
            PropertyDescriptor prop = props[i];
            table.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType);
        }
    }
    if (props != null)
    {
        object[] values = new object[props.Count];
        foreach (T item in data)
        {
            for (int i = 0; i < values.Length; i++)
            {
                values[i] = props[i].GetValue(item) ?? DBNull.Value;
            }
            table.Rows.Add(values);
        }
    }
    return table;
}

2
  using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Data;
using System.ComponentModel;

public partial class Default3 : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        DataTable dt = new DataTable();
        dt = lstEmployee.ConvertToDataTable();
    }
    public static DataTable ConvertToDataTable<T>(IList<T> list) where T : class
    {
        try
        {
            DataTable table = CreateDataTable<T>();
            Type objType = typeof(T);
            PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(objType);
            foreach (T item in list)
            {
                DataRow row = table.NewRow();
                foreach (PropertyDescriptor property in properties)
                {
                    if (!CanUseType(property.PropertyType)) continue;
                    row[property.Name] = property.GetValue(item) ?? DBNull.Value;
                }

                table.Rows.Add(row);
            }
            return table;
        }
        catch (DataException ex)
        {
            return null;
        }
        catch (Exception ex)
        {
            return null;
        }

    }
    private static DataTable CreateDataTable<T>() where T : class
    {
        Type objType = typeof(T);
        DataTable table = new DataTable(objType.Name);
        PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(objType);
        foreach (PropertyDescriptor property in properties)
        {
            Type propertyType = property.PropertyType;
            if (!CanUseType(propertyType)) continue;

            //nullables must use underlying types
            if (propertyType.IsGenericType && propertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
                propertyType = Nullable.GetUnderlyingType(propertyType);
            //enums also need special treatment
            if (propertyType.IsEnum)
                propertyType = Enum.GetUnderlyingType(propertyType);
            table.Columns.Add(property.Name, propertyType);
        }
        return table;
    }


    private static bool CanUseType(Type propertyType)
    {
        //only strings and value types
        if (propertyType.IsArray) return false;
        if (!propertyType.IsValueType && propertyType != typeof(string)) return false;
        return true;
    }
}

2

Bunun bir süredir kapalı olduğunun farkındayım; ancak, bu özel soruna bir çözüm vardı ama hafif bir bükülme gerekiyordu: sütunlar ve veri tablosu önceden tanımlanmış / zaten başlatılması gerekiyordu. Sonra sadece veri tablosuna türleri eklemek gerekiyordu.

İşte yaptığımın bir örneği:

public static class Test
{
    public static void Main()
    {
        var dataTable = new System.Data.DataTable(Guid.NewGuid().ToString());

        var columnCode = new DataColumn("Code");
        var columnLength = new DataColumn("Length");
        var columnProduct = new DataColumn("Product");

        dataTable.Columns.AddRange(new DataColumn[]
            {
                columnCode,
                columnLength,
                columnProduct
            });

        var item = new List<SomeClass>();

        item.Select(data => new
        {
            data.Id,
            data.Name,
            data.SomeValue
        }).AddToDataTable(dataTable);
    }
}

static class Extensions
{
    public static void AddToDataTable<T>(this IEnumerable<T> enumerable, System.Data.DataTable table)
    {
        if (enumerable.FirstOrDefault() == null)
        {
            table.Rows.Add(new[] {string.Empty});
            return;
        }

        var properties = enumerable.FirstOrDefault().GetType().GetProperties();

        foreach (var item in enumerable)
        {
            var row = table.NewRow();
            foreach (var property in properties)
            {
                row[property.Name] = item.GetType().InvokeMember(property.Name, BindingFlags.GetProperty, null, item, null);
            }
            table.Rows.Add(row);
        }
    }
}

bana örnek gösterebilir misin? addtodataTable () yöntemleri için uzantı yöntemini nasıl kullanırım
Abhishek B.

Bu kodun içinde zaten bir örnek var - Main () yöntemine bir göz atın. Kodun son biti kullanılan uzantıya sahip.
brenton

Daha fazla bilgi için lütfen MSDN'den uzantı yöntemleri hakkında bu makaleye bakın
brenton

2

.NET Core kullanıyorsanız 2019 cevabı - Nuget ToDataTable kütüphanesini kullanın . Avantajları:

Yasal Uyarı - ToDataTable'ın yazarıyım

Performans - Benchmark .Net testlerinden bazılarını kapsar ve ToDataTable deposuna ekledim . Sonuçlar aşağıdaki gibidir:

100.000 Sıralı Veri Tablosu Oluşturma :

                           MacOS         Windows
Reflection                 818.5 ms      818.3 ms
FastMember from           1105.5 ms      976.4 ms
 Mark's answer
Improved FastMember        524.6 ms      456.4 ms
ToDataTable                449.0 ms      376.5 ms

Önerilen FastMember yöntemi Marc'ın cevap daha kötü performans gibiydi Mary'nin cevap yansıması kullanılan, ancak başka bir yöntemi haddelenmiş bir FastMember kullanarak TypeAccessorve çok iyi performans gösterdi. Yine de ToDataTable paketi partiden daha iyi performans gösterdi.


1

VB.NET kullanıyorsanız, bu sınıf işi yapar.

Imports System.Reflection
''' <summary>
''' Convert any List(Of T) to a DataTable with correct column types and converts Nullable Type values to DBNull
''' </summary>

Public Class ConvertListToDataset

    Public Function ListToDataset(Of T)(ByVal list As IList(Of T)) As DataTable

        Dim dt As New DataTable()
        '/* Create the DataTable columns */
        For Each pi As PropertyInfo In GetType(T).GetProperties()
            If pi.PropertyType.IsValueType Then
                Debug.Print(pi.Name)
            End If
            If IsNothing(Nullable.GetUnderlyingType(pi.PropertyType)) Then
                dt.Columns.Add(pi.Name, pi.PropertyType)
            Else
                dt.Columns.Add(pi.Name, Nullable.GetUnderlyingType(pi.PropertyType))
            End If
        Next

        '/* Populate the DataTable with the values in the Items in List */
        For Each item As T In list
            Dim dr As DataRow = dt.NewRow()
            For Each pi As PropertyInfo In GetType(T).GetProperties()
                dr(pi.Name) = IIf(IsNothing(pi.GetValue(item)), DBNull.Value, pi.GetValue(item))
            Next
            dt.Rows.Add(dr)
        Next
        Return dt

    End Function

End Class

1

sınıfınızda özellikleri varsa bu kod satırı tamam !!

PropertyDescriptorCollection props =
            TypeDescriptor.GetProperties(typeof(T));

ancak tüm ortak alanlarınız varsa bunu kullanın:

public static DataTable ToDataTable<T>(  IList<T> data)
        {
        FieldInfo[] myFieldInfo;
        Type myType = typeof(T);
        // Get the type and fields of FieldInfoClass.
        myFieldInfo = myType.GetFields(BindingFlags.NonPublic | BindingFlags.Instance
            | BindingFlags.Public);

        DataTable dt = new DataTable();
        for (int i = 0; i < myFieldInfo.Length; i++)
            {
            FieldInfo property = myFieldInfo[i];
            dt.Columns.Add(property.Name, property.FieldType);
            }
        object[] values = new object[myFieldInfo.Length];
        foreach (T item in data)
            {
            for (int i = 0; i < values.Length; i++)
                {
                values[i] = myFieldInfo[i].GetValue(item);
                }
            dt.Rows.Add(values);
            }
        return dt;
        }

orijinal cevap yukarıdan, ben özellikleri yerine alanları kullanmak için sadece düzenlenmiş

ve onu kullanmak için

 DataTable dt = new DataTable();
            dt = ToDataTable(myBriefs);
            gridData.DataSource = dt;
            gridData.DataBind();

1

Genel listeyi veri tablosuna dönüştürmek için, DataTableGenerator

Bu kütüphane, listenizi aşağıdakiler gibi çok özellikli bir veri tablosuna dönüştürmenizi sağlar:

  • Veri tablosu başlığını çevir
  • gösterilecek bir sütun belirtin

1
  private DataTable CreateDataTable(IList<T> item)
        {
            Type type = typeof(T);
            var properties = type.GetProperties();

            DataTable dataTable = new DataTable();
            foreach (PropertyInfo info in properties)
            {
                dataTable.Columns.Add(new DataColumn(info.Name, Nullable.GetUnderlyingType(info.PropertyType) ?? info.PropertyType));
            }

            foreach (T entity in item)
            {
                object[] values = new object[properties.Length];
                for (int i = 0; i < properties.Length; i++)
                {
                    values[i] = properties[i].GetValue(entity);
                }

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

1

Genel listeyi DataTable'a dönüştürmek için

Newtonsoft.Json kullanarak;

public DataTable GenericToDataTable(IList<T> list)
{
    var json = JsonConvert.SerializeObject(list);
    DataTable dt = (DataTable)JsonConvert.DeserializeObject(json, (typeof(DataTable)));
    return dt;
}

0

Bu Listelenebilir Datatable dönüştürmek için basit Konsol Uygulamasıdır.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.ComponentModel;

namespace ConvertListToDataTable
{
    public static class Program
    {
        public static void Main(string[] args)
        {
            List<MyObject> list = new List<MyObject>();
            for (int i = 0; i < 5; i++)
            {
                list.Add(new MyObject { Sno = i, Name = i.ToString() + "-KarthiK", Dat = DateTime.Now.AddSeconds(i) });
            }

            DataTable dt = ConvertListToDataTable(list);
            foreach (DataRow row in dt.Rows)
            {
                Console.WriteLine();
                for (int x = 0; x < dt.Columns.Count; x++)
                {
                    Console.Write(row[x].ToString() + " ");
                }
            }
            Console.ReadLine();
        }

        public class MyObject
        {
            public int Sno { get; set; }
            public string Name { get; set; }
            public DateTime Dat { get; set; }
        }

        public static DataTable ConvertListToDataTable<T>(this List<T> iList)
        {
            DataTable dataTable = new DataTable();
            PropertyDescriptorCollection props = TypeDescriptor.GetProperties(typeof(T));
            for (int i = 0; i < props.Count; i++)
            {
                PropertyDescriptor propertyDescriptor = props[i];
                Type type = propertyDescriptor.PropertyType;

                if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
                    type = Nullable.GetUnderlyingType(type);

                dataTable.Columns.Add(propertyDescriptor.Name, type);
            }
            object[] values = new object[props.Count];
            foreach (T iListItem in iList)
            {
                for (int i = 0; i < values.Length; i++)
                {
                    values[i] = props[i].GetValue(iListItem);
                }
                dataTable.Rows.Add(values);
            }
            return dataTable;
        }
    }
}

0

Kampanyalar nampos con método para que acepte null.

// remove "this" if not on C# 3.0 / .NET 3.5
    public static DataTable ToDataTable<T>(IList<T> data)
    {
        PropertyDescriptorCollection props =
            TypeDescriptor.GetProperties(typeof(T));
        DataTable table = new DataTable();
        Type Propiedad = null;
        for (int i = 0; i < props.Count; i++)
        {
            PropertyDescriptor prop = props[i];
            Propiedad = prop.PropertyType;
            if (Propiedad.IsGenericType && Propiedad.GetGenericTypeDefinition() == typeof(Nullable<>)) 
            {
                Propiedad = Nullable.GetUnderlyingType(Propiedad);
            }
            table.Columns.Add(prop.Name, Propiedad);
        }
        object[] values = new object[props.Count];
        foreach (T item in data)
        {
            for (int i = 0; i < values.Length; i++)
            {
                values[i] = props[i].GetValue(item);
            }
            table.Rows.Add(values);
        }
        return table;
    }

2
Stack Overflow'a hoş geldiniz . Bu İngilizce konuşan bir web sitesi, bu yüzden lütfen cevaplarınızı İngilizce olarak da yazın.
Peri

0
 Dim counties As New List(Of County)
 Dim dtCounties As DataTable
 dtCounties = _combinedRefRepository.Get_Counties()
 If dtCounties.Rows.Count <> 0 Then
    For Each row As DataRow In dtCounties.Rows
      Dim county As New County
      county.CountyId = row.Item(0).ToString()
      county.CountyName = row.Item(1).ToString().ToUpper()
      counties.Add(county)
    Next
    dtCounties.Dispose()
 End If

0

Bence daha rahat ve kullanımı kolay.

   List<Whatever> _lobj= new List<Whatever>(); 
    var json = JsonConvert.SerializeObject(_lobj);
                DataTable dt = (DataTable)JsonConvert.DeserializeObject(json, (typeof(DataTable)));

0

Liste / veri = yeni Liste (); var dataDT = Newtonsoft.Json.JsonConvert.DeserializeObject (Newtonsoft.Json.JsonConvert.SerializeObject (veri));



0

Yansımayı kullanmak ve sütun sırasını ayarlamak / yalnızca bazı sütunlar eklemek / Bazı sütunları hariç tutmak için şunu deneyin:

        private static DataTable ConvertToDataTable<T>(IList<T> data, string[] fieldsToInclude = null,
string[] fieldsToExclude = null)
    {
        PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(typeof(T));
        DataTable table = new DataTable();
        foreach (PropertyDescriptor prop in properties)
        {
            if ((fieldsToInclude != null && !fieldsToInclude.Contains(prop.Name)) ||
                (fieldsToExclude != null && fieldsToExclude.Contains(prop.Name)))
                continue;
            table.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType);
        }

        foreach (T item in data)
        {
            var atLeastOnePropertyExists = false;
            DataRow row = table.NewRow();
            foreach (PropertyDescriptor prop in properties)
            {

                if ((fieldsToInclude != null && !fieldsToInclude.Contains(prop.Name)) ||
(fieldsToExclude != null && fieldsToExclude.Contains(prop.Name)))
                    continue;

                row[prop.Name] = prop.GetValue(item) ?? DBNull.Value;
                atLeastOnePropertyExists = true;
            }

            if(atLeastOnePropertyExists) table.Rows.Add(row);
        }


        if (fieldsToInclude != null)
            SetColumnsOrder(table, fieldsToInclude);

        return table;

    }

    private static void SetColumnsOrder(DataTable table, params String[] columnNames)
    {
        int columnIndex = 0;
        foreach (var columnName in columnNames)
        {
            table.Columns[columnName].SetOrdinal(columnIndex);
            columnIndex++;
        }
    }
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.