Die akzeptierte Antwort beschreibt korrekt, wie die Liste deklariert werden soll, und wird für die meisten Szenarien dringend empfohlen.
Ich bin jedoch auf ein anderes Szenario gestoßen, das auch die gestellte Frage abdeckt. Was ist, wenn Sie eine vorhandene Objektliste wie ViewData["htmlAttributes"]
in MVC verwenden müssen ? Wie können Sie auf seine Eigenschaften zugreifen (sie werden normalerweise über erstellt new { @style="width: 100px", ... }
)?
Für dieses etwas andere Szenario möchte ich Ihnen mitteilen, was ich herausgefunden habe. In den folgenden Lösungen gehe ich von folgender Erklärung aus für nodes
:
List<object> nodes = new List<object>();
nodes.Add(
new
{
Checked = false,
depth = 1,
id = "div_1"
});
1. Lösung mit Dynamik
In C # 4.0 und höheren Versionen können Sie einfach in dynamisch umwandeln und schreiben:
if (nodes.Any(n => ((dynamic)n).Checked == false))
Console.WriteLine("found not checked element!");
Hinweis: Hierbei wird eine späte Bindung verwendet. Dies bedeutet, dass nur zur Laufzeit erkannt wird, wenn das Objekt keine Checked
Eigenschaft hat, und RuntimeBinderException
in diesem Fall eine ausgelöst wird. Wenn Sie also versuchen, eine nicht vorhandene Checked2
Eigenschaft zu verwenden, wird die folgende Meldung angezeigt Laufzeit : "'<>f__AnonymousType0<bool,int,string>' does not contain a definition for 'Checked2'"
.
2. Lösung mit Reflexion
Die Lösung mit Reflection funktioniert sowohl mit alten als auch mit neuen C # -Compilerversionen . Bei alten C # -Versionen beachten Sie bitte den Hinweis am Ende dieser Antwort.
Hintergrund
Als Ausgangspunkt habe ich hier eine gute Antwort gefunden . Die Idee ist, den anonymen Datentyp mithilfe von Reflection in ein Wörterbuch zu konvertieren. Das Wörterbuch erleichtert den Zugriff auf die Eigenschaften, da deren Namen als Schlüssel gespeichert sind (Sie können wie darauf zugreifen myDict["myProperty"]
).
Angeregt durch den Code in dem obigen Link, habe ich eine Erweiterungsklasse bietet GetProp
, UnanonymizeProperties
und UnanonymizeListItems
als Erweiterungsmethoden, die simplify Zugriff auf anonyme Eigenschaften. Mit dieser Klasse können Sie die Abfrage einfach wie folgt ausführen:
if (nodes.UnanonymizeListItems().Any(n => (bool)n["Checked"] == false))
{
Console.WriteLine("found not checked element!");
}
oder Sie können den Ausdruck nodes.UnanonymizeListItems(x => (bool)x["Checked"] == false).Any()
als if
Bedingung verwenden, die implizit filtert und dann prüft, ob Elemente zurückgegeben werden.
Um das erste Objekt mit der Eigenschaft "Überprüft" abzurufen und seine Eigenschaft "Tiefe" zurückzugeben, können Sie Folgendes verwenden:
var depth = nodes.UnanonymizeListItems()
?.FirstOrDefault(n => n.Contains("Checked")).GetProp("depth");
oder kürzer: nodes.UnanonymizeListItems()?.FirstOrDefault(n => n.Contains("Checked"))?["depth"];
Hinweis: Wenn Sie eine Liste von Objekten haben, die nicht unbedingt alle Eigenschaften enthalten müssen (zum Beispiel enthalten einige nicht die Eigenschaft "Geprüft"), und Sie dennoch eine Abfrage basierend auf "Geprüften" Werten erstellen möchten, können Sie dies tun mach das:
if (nodes.UnanonymizeListItems(x => { var y = ((bool?)x.GetProp("Checked", true));
return y.HasValue && y.Value == false;}).Any())
{
Console.WriteLine("found not checked element!");
}
Dies verhindert, dass a KeyNotFoundException
auftritt, wenn die Eigenschaft "Checked" nicht vorhanden ist.
Die folgende Klasse enthält die folgenden Erweiterungsmethoden:
UnanonymizeProperties
: Wird verwendet, um die in einem Objekt enthaltenen Eigenschaften zu de-anonymisieren . Diese Methode verwendet Reflexion. Es konvertiert das Objekt in ein Wörterbuch, das die Eigenschaften und seine Werte enthält.
UnanonymizeListItems
: Wird verwendet, um eine Liste von Objekten in eine Liste von Wörterbüchern zu konvertieren, die die Eigenschaften enthalten. Es kann optional einen Lambda-Ausdruck enthalten, der zuvor gefiltert werden soll.
GetProp
: Wird verwendet, um einen einzelnen Wert zurückzugeben, der dem angegebenen Eigenschaftsnamen entspricht. Ermöglicht die Behandlung nicht vorhandener Eigenschaften als Nullwerte (true) und nicht als KeyNotFoundException (false).
Für die obigen Beispiele müssen Sie lediglich die folgende Erweiterungsklasse hinzufügen:
public static class AnonymousTypeExtensions
{
// makes properties of object accessible
public static IDictionary UnanonymizeProperties(this object obj)
{
Type type = obj?.GetType();
var properties = type?.GetProperties()
?.Select(n => n.Name)
?.ToDictionary(k => k, k => type.GetProperty(k).GetValue(obj, null));
return properties;
}
// converts object list into list of properties that meet the filterCriteria
public static List<IDictionary> UnanonymizeListItems(this List<object> objectList,
Func<IDictionary<string, object>, bool> filterCriteria=default)
{
var accessibleList = new List<IDictionary>();
foreach (object obj in objectList)
{
var props = obj.UnanonymizeProperties();
if (filterCriteria == default
|| filterCriteria((IDictionary<string, object>)props) == true)
{ accessibleList.Add(props); }
}
return accessibleList;
}
// returns specific property, i.e. obj.GetProp(propertyName)
// requires prior usage of AccessListItems and selection of one element, because
// object needs to be a IDictionary<string, object>
public static object GetProp(this object obj, string propertyName,
bool treatNotFoundAsNull = false)
{
try
{
return ((System.Collections.Generic.IDictionary<string, object>)obj)
?[propertyName];
}
catch (KeyNotFoundException)
{
if (treatNotFoundAsNull) return default(object); else throw;
}
}
}
Hinweis: Der obige Code verwendet die seit C # Version 6.0 verfügbaren nullbedingten Operatoren. Wenn Sie mit älteren C # -Compilern (z. B. C # 3.0) arbeiten, ersetzen Sie diese einfach ?.
nach .
und ?[
nach [
, z
var depth = nodes.UnanonymizeListItems()
.FirstOrDefault(n => n.Contains("Checked"))["depth"];
Wenn Sie nicht gezwungen sind, einen älteren C # -Compiler zu verwenden, behalten Sie diesen unverändert bei, da die Verwendung von Nullbedingungen die Nullbehandlung erheblich vereinfacht.
Hinweis: Wie bei der anderen Lösung mit dynamischer Funktion wird auch bei dieser Lösung eine späte Bindung verwendet. In diesem Fall wird jedoch keine Ausnahme angezeigt. Das Element wird einfach nicht gefunden, wenn Sie auf eine nicht vorhandene Eigenschaft verweisen wie Sie die nullbedingten Operatoren behalten .
Für einige Anwendungen kann es nützlich sein, dass auf die Eigenschaft in Lösung 2 über eine Zeichenfolge verwiesen wird und sie daher parametrisiert werden kann.