2009-09-10 12 views
5

Widziałem następującą funkcję w delegowania który pozwala zamówić dane przy użyciu rodzajowe wyrażenie:Problem z funkcją Generic LINQ OrderBy

public static IOrderedQueryable<T> OrderBy<T, TKey>(
    this IQueryable<T> source, Expression<Func<T, TKey>> func, bool isDescending) { 
    return isDescending ? source.OrderByDescending(func) : source.OrderBy(func); 
} 

Kiedy próbuję użyć tej funkcji pojawia się błąd mówiący „The typ lub nazwa przestrzeni nazw „TKey” nie można odnaleźć (czy brakuje using dyrektywa lub odwołania do zestawu?)”robię coś głupiego tutaj, ale nie mogę zrozumieć to

Edycja:..

Po wykonaniu nieco więcej badań, myślę, że moim problemem jest budowanie Expr epoka, którą do niej przechodzę. Czy można zbudować wyrażenie, które może zawierać różne typy? Powiedzmy, że mój zbiór danych ma ciąg, int i bool i chcę użyć powyższej funkcji ogólnej do sortowania według dowolnego z elementów. Jak mam to zrobic?

mam to działa teraz:

if (IsString) 
{ 
    Expression<Func<T, string>> expString = ...; 
    // call orderBy with expString 
} 
else if (IsInt) 
{ 
    Expression<Func<T, int>> expInt; 
    // call orderBy w/ expInt 
} 
: 

chcę coś takiego:

Expression<Func<T, {something generic!}>> exp; 
if (IsString) 
    exp = ...; 
else if (IsInt) 
    exp = ...; 
: 
// call orderBy with exp 
+0

Wydaje się to w porządku. W jaki sposób używasz tej metody? Czy dodałeś go do klasy statycznej? – BFree

Odpowiedz

2

Moim celem było wyeliminowanie wielu powtarzających się kodów. Oprócz obsługi rosnącej/malejącej, moja funkcja "OrderBy" radzi sobie dobrze z innymi typowymi logikami. Zakładając definicję funkcji w oryginalnym delegowania, można po prostu to zrobić:

if ({need to sort by integer}) 
    query = OrderBy(objectT, a => a.myIntegerField, asc); 
else if ({need to sort by string}) 
    query = OrderBy(objectT, a=> a.myStringField, asc); 
: 
1

Wyrażenie może mieć tylko jeden typ; moja odpowiedź tutaj korzystne byłoby coś takiego:

IQueryable<T> query = ... 
if({case 1}) { 
    query = query.OrderBy(x=>x.SomeValue); 
} else if({case 2}) { 
    query = query.OrderBy(x=>x.SomeOtherValue); 
} ... 

Jednakże, jeśli chcesz zrobić coś bardziej elastyczne, to prawdopodobnie trzeba dostać się do niestandardowych Expression piśmie; coś more like this.

+0

To było to, co pierwotnie miałem, ale skończyło się na tonie "zduplikowanego" kodu, ponieważ mam wiele pól i muszę obsługiwać sortowanie rosnąco/malejąco. Wydana przeze mnie odpowiedź wydaje się działać dobrze. – ejwipp

4

jeden szybki obserwację: Tak naprawdę nie trzeba używać wyrażenia lambda (Expression<Func<T,TKey>>). Prosty delegat (Func<T,TKey>) jest w porządku.

Mimo to, myślę, że odpowiedź może być patrząc na to:

Func<T,IComparable> func = null; 
if (IsString) 
    func = (T a) => a.SomeStringValue; 
else if (IsInt) 
    func = (T a) => a.SomeIntValue; 
// call orderBy with exp 
+0

Wygląda na to, co szukałem. Jednak trochę się z tym bawiłem i nie mogłem go skompilować. Kiedy próbuję przekazać func do funkcji OrderBy, kompilator narzeka. Twoja metoda byłaby nieco czystsza, gdyby działała, ale niestety nie mogę teraz poświęcić jej więcej czasu. – ejwipp

+1

Gdy masz czas, proszę powiedz mi, jaki jest błąd kompilatora, który widzisz. – jpbochi

+0

W końcu wróciłem do tego. Myślę, że problem polega na tym, że w mojej funkcji customBey wywołuję funkcję ThenBy, która nie przyjmuje argumentu Func - wymaga wyrażenia lambda. – ejwipp

0

Spójrz na this answer

Moja rodzajowy obsługi dla sortowania jest:

  • "dgvProcessList" jest moim dataGridView
  • "Proces" jest moim celem zbindowanych niej
  • "E" jest moje DataGridViewCellMouseEventArgs

      PropertyInfo column = (new Process()).GetType().GetProperties().Where(x => x.Name == dgvProcessList.Columns[e.ColumnIndex].Name).First(); 
         if (isSortedASC == true) 
          dgvProcessList.DataSource = ((List<Process>)dgvProcessList.DataSource).OrderByDescending(x => column.GetValue(x, null)).ToList(); 
         else 
          dgvProcessList.DataSource = ((List<Process>)dgvProcessList.DataSource).OrderBy(x => column.GetValue(x, null)).ToList(); 
    
         isSortedASC = !isSortedASC; 
         dgvProcessList.ClearSelection(); 
    

Pozdrowienia