Feedback

C# - Verschachtelte Klasseninstanzen rekursiv durchsuchen

Veröffentlicht von am 21.11.2015
(0 Bewertungen)
Manchmal gibt es die Problematik, dass Klassen Properties vom Typ der Klasse selbst halten. Das heißt letztendlich natürlich auch, dass Instanzen dieser Klasse "in sich selbst verschachtelt" werden können.
Beispiel:

  //Klasse zum Halten der Daten
public class Test
{
public Test()
{

}

public Test InnerTest { get; set; }
public string Text { get; set; }
public int Count { get; set; }
}

class Program
{
public static void Main()
{
//Verschachtelung erzeugen
Test foobar = new Test()
{
Text = "Level1",
InnerTest = new Test()
{
Text = "Level2",
Count = 33,
InnerTest = new Test()
{
InnerTest = new Test()
{
Text = "Level3",
Count = 44
}
}
}
};

//Instanzen des Properties "Text" mit dem Wert "Level3" suchen
IEnumerable<Test> level3Result = foobar.DeepWhere(p => p.Text == "Level3");
//Instanzen des Properties "Count" mit dem Wert "33" suchen
IEnumerable<Test> countResult = foobar.DeepWhere(p => p.Count == 33);
}
}

Dieses Snippet dient dazu, diese "Verschachtelung" aufzulösen und die verschiedenen Instanzen durchsuchen zu können.
Die eigentliche Funktionalität stellt die Extension-Function "DeepWhere" bereit. Diese Methode liefert ein IEnumerable der Instanzen zurück, die den angegebenen Suchkritieren entsprechen.

Das entsprechende Snippet erfordert die .NET-Framework Version 4.5
GFU-Schulungen  [Anzeige]

ASP.NET Core - Der Einstieg

In nur 3 Tagen lernen Sie, wie man mit ASP.NET Core und den Technologien MVC, Entity Framework, WebAPI und Razor professionelle Web-Anwendungs-Architekturen aufbaut. Diese Schulung ist der perfekte Einstieg, um datengetriebene und präsentations-orientierte Applikationen auf Basis der ASP.NET Core Plattform zu erstellen.

Visual Studio Team Foundation Server 2017/2015 (TFS) für Projektmitglieder - Kompakt

Nach Teilnahme an dieser Schulung sind Ihnen die Grundlagen von ALM geläufig. Sie planen und steuern Projekte effizient mit dem Visual Studio Team Foundation Server.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

  public static class Extension
  {
    /// <summary>
    /// Filters a sequence of values recursive based on a predicate. 
    /// </summary>
    /// <param name="predicate">A function to test each element for a condition.</param>
    /// <returns>An IEnumerable that contains elements from the input sequence that satisfy the condition.</returns>
    public static IEnumerable<TSource> DeepWhere<TSource>(this TSource instance, Func<TSource, bool> predicate)
    {
      if (instance != null)
      {
        if (predicate(instance))
          yield return instance;

        foreach (TSource source in instance
          .GetType().GetProperties()
          .Where(p => p.PropertyType.Equals(typeof(TSource)))
          .SelectMany(p => ((TSource)p.GetValue(instance)).DeepWhere(predicate)))
          yield return source;
      }
    }
  }
Abgelegt unter c#.

2 Kommentare zum Snippet

Anonymous2 schrieb am 22.11.2015:
Das Problem per Reflection zu lösen ist recht langsam. Linq ähnlich könnte man es so aufbauen:

IEnumerable<T> IterateChain<T>(T obj, Func<T, T> what, Func<T, bool> when) where T : class
{
if (obj == null)
{
throw new ArgumentNullException(nameof(obj));
}

T current = obj;
while (true)
{
current = what(current);
if (current == null)
{
break;
}
if (when == null || when(current))
{
yield return current;
}
else
{
break;
}
}
}

//das entspricht deinem foobar.Search("Count", 33)
foreach (var t in IterateChain(foobar, t => t.InnerTest, t => t.Count == 33))
{
Console.WriteLine(t.Text);
}


Edit: Im Code sind ein paar spitze Klammern drin, leider werden die hier in dem Kommentar nicht angezeigt: http://pastebin.com/sj2VN7tL
floriankolb schrieb am 22.11.2015:
Danke für die Anregung! Eine Func ist dafür perfekt geeignet. Ich habe meinen Code ein bisschen angepasst
 

Logge dich ein, um hier zu kommentieren!