Autor Beitrag
Biplane
Hält's aus hier
Beiträge: 9



BeitragVerfasst: Mo 17.11.08 16:06 
Moinmoin,

derzeit kämpfe ich mit dem Problem der dynamischen Sortierung eines IEnumarable herum...

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
List<Daten> wertList = new List<daten>();
wertList.Add(new Daten{ wert = "test5"});
wertList.Add(new Daten{ wert = "test3"});
wertList.Add(new Daten{ wert = "test2"});
wertList.Add(new Daten{ wert = "test7"});

var x = wertList.OrderBy("wert"true);

foreach (var c in x)
{
    System.Diagnostics.Debug.WriteLine(c.wert);
}


Dieses Beispiel funktioniert (zusammen mit untenstehendem Quellcode) einwandfrei, solange "wertList" vom Typ "List<Daten>" oder "IEnumerable<Daten>" ist.

Das Problem ist aber, das ich in meinem Assembly, wo dieser Quellcode ausgeführt werden soll, nicht den Typ "Daten" kenne, sondern nur auf IEnumerable (var wertList = daten as IEnumerable) konvertieren kann. Bei IEnumerable funktionieren aber die Erweiterungsmethoden nicht.

Kennt jemand eine Lösung ? Im Zweifelsfall zur not auch ohne LinqToObjects.

Gruß
Norbert


ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
public static class DynamicEnumerable
{
    public static IEnumerable<T> OrderBy<T>(this IEnumerable<T> query, string propertyName, bool ascending)
    {
        ParameterExpression prm = System.Linq.Expressions.Expression.Parameter(typeof(T), "it");

        System.Linq.Expressions.Expression property = System.Linq.Expressions.Expression.Property(prm, propertyName);

        Type propertyType = property.Type;

        MethodInfo method = typeof(DynamicEnumerable).GetMethod("OrderByProperty", BindingFlags.Static | BindingFlags.NonPublic)
            .MakeGenericMethod(typeof(T), propertyType);

        return (IEnumerable<T>)method.Invoke(nullnew object[] { query, prm, property, ascending });
    }

    private static IEnumerable<T> OrderByProperty<T, P>(this IEnumerable<T> query, ParameterExpression prm, System.Linq.Expressions.Expression property, bool ascending)
    {
        Func<IEnumerable<T>, Func<T, P>, IEnumerable<T>> orderBy = (q, p) => ascending ? q.OrderBy(p) : q.OrderByDescending(p);
        return orderBy(query, System.Linq.Expressions.Expression.Lambda<Func<T, P>>(property, prm).Compile());
    }
}

class Daten
{
    public string wert
    {
        get;
        set;
    }
}


Moderiert von user profile iconChristian S.: C#-Tags hinzugefügt
Kha
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 3803
Erhaltene Danke: 176

Arch Linux
Python, C, C++ (vim)
BeitragVerfasst: Mo 17.11.08 17:45 
user profile iconBiplane hat folgendes geschrieben Zum zitierten Posting springen:
Das Problem ist aber, das ich in meinem Assembly, wo dieser Quellcode ausgeführt werden soll, nicht den Typ "Daten" kenne, sondern nur auf IEnumerable (var wertList = daten as IEnumerable) konvertieren kann.
Weshalb? Hört sich für mich nicht ganz sinnig an.
Wie auch immer: Nach einem .Cast<object>() solltest du auch IEnumerables an deine Methode schicken können.

_________________
>λ=
Biplane Threadstarter
Hält's aus hier
Beiträge: 9



BeitragVerfasst: Mo 17.11.08 18:15 
Hmm...

Folgende Varianten habe ich schon ausprobiert...

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
// Compiliert, wirft aber zur Laufzeit Exception beim Aufruf variante1.OrderBy("wert", true)
var variante1 = _List.Cast<object>();  

// Bei variante2.OrderBy("wert", true) wird beim compilieren OrderBy nicht gefunden.
IEnumerable variante2 = _List as IEnumerable;

// Compiliert nicht
IEnumerable<object> variante2 = _List as IEnumerable<object>;


Das ganze verwende ich in einer Assembly mit UserControls. Die Daten aus der Liste werden mittels Reflection bei einem TreeControl verwendet. Dies funktioniert prima, nur soll noch innerhalb einer Ebene/Ordner nach der anzuzeigenden Spalte sortiert werden.

So einfach scheint es wohl doch nicht zu sein.

Gruß
Norbert

Moderiert von user profile iconChristian S.: C#-Tags hinzugefügt
Kha
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 3803
Erhaltene Danke: 176

Arch Linux
Python, C, C++ (vim)
BeitragVerfasst: Mo 17.11.08 18:50 
user profile iconBiplane hat folgendes geschrieben Zum zitierten Posting springen:
ausblenden C#-Quelltext
1:
// Compiliert, wirft aber zur Laufzeit Exception beim Aufruf					
Jupp, nach weiterem Nachdenken ;) logisch. Wenn du nicht für jedes Item Reflection aufrufen willst (was in der GUI wahrscheinlich sogar noch erträglich sein sollte?), muss dein OrderBy-Ersatz (egal ob mit Linq oder nicht) den Typ der Liste kennen, also z.B. durch einen weiteren Type-Parameter. Oder du lässt die Quellen deiner dynamischen Listen IQueryable zurückgeben (.AsQueryable), denn dafür gibts schon fertige Lösungen: weblogs.asp.net/scot...c-query-library.aspx

_________________
>λ=
Biplane Threadstarter
Hält's aus hier
Beiträge: 9



BeitragVerfasst: Di 18.11.08 10:14 
Tja, das Problem bleibt unabhängig von IQueryable oder IEnumerable gleich. Der Quelltext von deinem Linq "static class DynamicQueryable" ist grundsätzlich die gleiche vorgehensweise, die ich im Initialbeitrag mit "DynamicEnumerable" gegangen bin. Das funktioniert so leider nicht. Ohne bekannten Typ, kommt man wohl nicht an die zu sortierende Spalte ran.

Zwei mögliche Lösugen fallen mir noch ein:
1. Einen größer-Operator implementieren, der intern über Reflection auf die zu Sortierende Spalte zugreift und dann drum herum einen Sortieralgorhytmus bauen.
2. Die Verfügbare Liste (IEnumerable) in eine, dem Assembly bekannte, Klasse zu überführen:

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
class Sorthelper
{
public Sorthelper(Object object, String column)
{
// Wert mittels Reflection ermitteln object.column und der Property Wert zuweisen

}
public String Wert
{
get;
set;
}
}


Eine Liste von Sorthelper läst sich dann einfach sortieren.

Gruß
Norbert

Moderiert von user profile iconKha: C#-Tags hinzugefügt
Kha
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 3803
Erhaltene Danke: 176

Arch Linux
Python, C, C++ (vim)
BeitragVerfasst: Di 18.11.08 14:42 
user profile iconBiplane hat folgendes geschrieben Zum zitierten Posting springen:
Tja, das Problem bleibt unabhängig von IQueryable oder IEnumerable gleich.
Nein, IQueryable ist immer mit einem Typ verbunden (nämlich IQueryable.ElementType). Ich bin davon ausgegangen, dass irgendwo vor dem TreeView die Daten als IEnumerable<T> vorliegen, du sie also dort in IQueryable konvertieren kannst.
user profile iconBiplane hat folgendes geschrieben Zum zitierten Posting springen:
Zwei mögliche Lösugen fallen mir noch ein:

1. Einen größer-Operator implementieren, der intern über Reflection auf die zu Sortierende Spalte zugreift und dann drum herum einen Sortieralgorhytmus bauen.
2. Die Verfügbare Liste (IEnumerable) in eine, dem Assembly bekannte, Klasse zu überführen:
Also mit Reflection pro Item? Dann kannst du auch Linq2Objects benutzen:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
public static IEnumerable OrderByProperty(this IEnumerable self, string propertyName)
{
  return
    self.Cast<object>()
    .OrderBy(o => o.GetType().GetProperty(propertyName).GetValue(o, null));
}

_________________
>λ=