2014-12-30 14 views
5

Jestem nowy w LINQ i przeprowadzam z nim pewne eksperymenty.Zamień List.foreach na LINQ

Przepraszam, jeśli jest to duplikat, ale nie mogę wydawać się znaleźć właściwego przewodnika (dla mnie), aby go

chcę zastąpić ten kod:

DataTable table 
List<string> header = new List<string>(); 
table.Columns.Cast<DataColumn>().ToList().ForEach(col => header.Add(col.ColumnName)); 

z czymś LINQ jak:

var LINQheader = from mycol in table.Columns select mycol.ColumnName; 
LINQheader.tolist(); 

ale nie kompiluje się. co chcę nie jest jedno rozwiązanie linia ale chciałby pewnej logiki, aby zrozumieć, w jaki sposób skonstruować go z bardziej skomplikowanych środowiskach (jak wybór wielu węzeł XML z pewną logiką)

+0

Czy nie jest to powód, dla którego nie kompiluje się faktu, że masz 'table.column' w twoim linq instrukcji zamiast' table.Columns'? – DoctorMick

+0

@DoctorMam oczywiście, że to był tylko literówka (nie skopiowałem go z kodu, ale przepisuję go w pytaniu) Edytowane pytanie – LordTitiKaka

+0

Ciągle nie kompiluje się, ponieważ w Linq jest rozróżniana wielkość liter, zobacz moje odpowiedź. – VMAtm

Odpowiedz

3

tutaj jest oryginalny kod

table.Columns.Cast<DataColumn>().ToList().ForEach(col => header.Add(col.ColumnName)); 

Dlaczego Cast używane?
ponieważ pozwala traktować elementy DataColumnCollection jako obiekty nie będące obiektami DataColumn.

Dlaczego użyto ToList?
ponieważ konwertuje twój IEnumerable na List i umożliwia wywołanie ForEach, ponieważ ta funkcja jest specjalną metodą, która istnieje w klasie List.

Dlaczego użyto ?
ponieważ pozwala ci robić to, co chcesz dla każdego elementu na liście (w twoim przypadku dodaje nazwę kolumny każdej kolumny do innej listy (header)).

Uproszczona wersja:

Zakładamy teraz chcesz dodać nazwy kolumn do header gdzie zaczyna się „student” można napisać coś takiego

DataTable table = new DataTable(); 
List<string> header = new List<string>(); 

foreach (DataColumn col in table.Columns) 
{ 
    if (col.ColumnName.StartsWith("Id")) // you can remove this line if you want to add all of them 
     header.Add(col.ColumnName); 
} 

można również użyć tego

table.Columns.Cast<DataColumn>() 
    .ToList() 
    .ForEach(col => 
    { 
     if (col.ColumnName.StartsWith("Id")) 
      header.Add(col.ColumnName) 
    }); 

lub

var headers = table.Columns.Cast<DataColumn>() 
     .Where(col => col.ColumnName.StartsWith("Id")) 
     .Select(col => col.ColumnName); 

header.AddRange(headers); 
+1

W rzeczywistości są odpowiedzi są dobre, ale twoje (myślę) jest bardziej pouczające i logiczne – LordTitiKaka

3

Można użyć Enumerable.Aggregate() na to:

var header = table.Columns.Cast<DataColumn>().Aggregate(new List<string>(), (list, col) => { list.Add(col.ColumnName); return list; }); 

Ogólnie rzecz biorąc, Linq pozwala na pobieranie i przekształcanie sekwencji danych ze źródeł danych. To, co chcesz zrobić w tym pytaniu, to powtórzyć sekwencję i zwrócić natychmiastowy wynik. To nie jest główny cel Linq, ale istnieją metody, które wykonują tasks like this, w tym Aggregate(), Average(), Count(), Max() i tak dalej.

+0

co chcę Nie jest rozwiązaniem jednoliniowym, ale chciałbym, aby jakaś logika zrozumiała jak zbudować go w bardziej skomplikowanych środowiskach – dotctor

+1

@dotctor - czy jesteś OP? Jeśli mógłbyś wyjaśnić, co chciałbyś zrobić, może mógłbym pomóc więcej. – dbc

+0

Właśnie wkleiłem część OP dla ciebie, chcę, abyś pomógł temu, kto zadał to pytanie, myślę, że zrozumienie 'Agregacji' jest trudniejsze niż' ForEach'. – dotctor

1

Dlaczego nie prosty wybór jak

DataTable table; 
IEnumerable<string> header = from mycol in table.Columns.Cast<DataColumn>() 
          select mycol.ColumnName; 
2
var LINQheader = from mycol in table.column select mycol.ColumnName; 
LINQheader.tolist(); 

Nie będzie to skompilować jak istnieje taka nieruchomość w DataTable jako column nie istnieje tylko Columns i trzeba użyć .Cast() metody, ponieważ nie są wdrożenie właściwego interfejsu (patrz odpowiedź @ Uriil).

Spróbuj tego:

var LINQheader = from mycol in table.Columns.Cast<DataColumn>() 
        select mycol.ColumnName; 
LINQheader.tolist(); 

Jeśli chcesz użyć owinąć go w metodę rozszerzenia, można zrobić to tak:

public static IEnumerable<string> GetHeaderColumns (this DataTable dataTable) 
{ 
    if (dataTable == null || !dataTable.Columns.Any()) 
    { 
     yield break; 
    } 
    foreach (var col in dataTable.Columns.Cast<DataColumn>()) 
    { 
     yield return col.ColumnName; 
    } 
} 
+0

dla bardziej spójnego wdrożenia również jako metoda rozszerzenia dla DataTable :-) – Grundy

+1

@Grundy Tak, mój panie! – VMAtm

+1

metody rozszerzeń muszą być funkcjami statycznymi w klasach statycznych – dotctor

2
static void Main(string[] args) 
    { 
     DataTable tbl = new DataTable(); 
     tbl.Columns.Add("A"); 
     tbl.Columns.Add("B"); 

     var p = from DataColumn col in tbl.Columns select col.ColumnName; 

     foreach(string a in p) 
     { 
      Console.WriteLine(a); 
     } 
    } 

Oto mały przykład kodu. Jeśli chcesz być List<string>, użyj ToList().

EDIT:

Jak @Grundy mówi brakuje, aby określić typ kol, który jest DataColumn.

List<string> columnList = (from DataColumn mycol in table.Columns select mycol.ColumnName).ToList(); 

Tutaj będzie to Twoja linia.

+0

proszę dodać do odpowiedzi, że twój kod działa, ponieważ określasz typ 'DataColumn' dla zmiennej' col' w klauzuli select – Grundy

+0

@Grundy Zrobiłem to, myślę, że teraz jest bardziej zrozumiały :) – mybirthname

+0

tak, ja też tak myślę :-) – Grundy

1

mieć pewne problemy, które wymagają obejście:

  1. ForEach jest metoda specifict listy, więc nie można przełożyć je na LINQ
  2. LINQ jest do selekcji danych, agregacja, ale nie dla danych modyfikacji
  3. table.Columns powraca DataColumnCollection, które nie ma realizować IEnumerable<T>, więc trzeba będzie rzucić to tak:

    var LINQheader = from mycol in table.Columns.Cast<DataColumn>() 
           select name.ColumnName;