Sprache: C#
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:
[code] //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);
}
}
[/code]
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 [b].NET-Framework Version 4.5[/b]
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;
}
}
}
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;
}
}
}
Alte URL:
/snippet/verschachtelte-klasseninstanzen-rekursiv-durchsuchen/13090
Das Problem per Reflection zu lösen ist recht langsam. Linq ähnlich könnte man es so aufbauen:
[code]IEnumerable IterateChain (T obj, Func what, Func 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);
}[/code]
Edit: Im Code sind ein paar spitze Klammern drin, leider werden die hier in dem Kommentar nicht angezeigt: http://pastebin.com/sj2VN7tL
Danke für die Anregung! Eine Func ist dafür perfekt geeignet. Ich habe meinen Code ein bisschen angepasst