it-swarm.com.de

Wie kann auf eine Eigenschaft eines anonymen Typs in C # zugegriffen werden?

Ich habe das:

List<object> nodes = new List<object>(); 

nodes.Add(
new {
    Checked     = false,
    depth       = 1,
    id          = "div_" + d.Id
});

... und ich frage mich, ob ich dann die Eigenschaft "Checked" des anonymen Objekts verwenden kann. Ich bin mir nicht sicher, ob das überhaupt möglich ist. Versucht, dies zu tun:

if (nodes.Any(n => n["Checked"] == false)) ... aber es funktioniert nicht.

Vielen Dank

94
wgpubs

Wenn Sie eine stark typisierte Liste anonymer Typen benötigen, müssen Sie die Liste auch als anonymen Typ definieren. Der einfachste Weg, dies zu tun, ist das Projizieren einer Sequenz wie eines Arrays in eine Liste, z.

var nodes = (new[] { new { Checked = false, /* etc */ } }).ToList();

Dann können Sie darauf zugreifen:

nodes.Any(n => n.Checked);

Aufgrund der Funktionsweise des Compilers sollte das Folgende dann auch funktionieren, wenn Sie die Liste erstellt haben, da die anonymen Typen dieselbe Struktur haben und somit auch derselbe Typ sind. Ich habe keinen Compiler, um das zu überprüfen.

nodes.Add(new { Checked = false, /* etc */ });
54
Greg Beech

Wenn Sie das Objekt als Typ object speichern, müssen Sie die Reflektion verwenden. Dies gilt für jeden Objekttyp, anonym oder anderweitig. Auf einem Objekt o können Sie seinen Typ abrufen:

Type t = o.GetType();

Dann suchen Sie eine Immobilie:

PropertyInfo p = t.GetProperty("Foo");

Dann können Sie daraus einen Wert erhalten:

object v = p.GetValue(o, null);

Diese Antwort ist für ein Update für C # 4 längst überfällig:

dynamic d = o;
object v = d.Foo;

Und jetzt noch eine Alternative in C # 6:

object v = o?.GetType().GetProperty("Foo")?.GetValue(o, null);

Beachten Sie, dass durch die Verwendung von ?. die resultierende v in drei verschiedenen Situationen null ist! 

  1. o ist null, es gibt also überhaupt kein Objekt
  2. o ist keine -null, besitzt aber keine Eigenschaft Foo
  3. o hat eine Eigenschaft Foo, aber ihr tatsächlicher Wert ist null.

Dies ist also nicht gleichbedeutend mit den vorherigen Beispielen, kann aber sinnvoll sein, wenn Sie alle drei Fälle gleich behandeln möchten.

225

Sie können die Eigenschaften des anonymen Typs mithilfe von Reflection durchlaufen. Sehen Sie nach, ob es eine "Checked" -Eigenschaft gibt, und geben Sie dann deren Wert an.

Siehe diesen Blogeintrag: http://blogs.msdn.com/wriju/archive/2007/10/26/c-3-0-anonymous-type-and-net-reflection-hand-in- hand.aspx

So etwas wie:

foreach(object o in nodes)
{
    Type t = o.GetType();

    PropertyInfo[] pi = t.GetProperties(); 

    foreach (PropertyInfo p in pi)
    {
        if (p.Name=="Checked" && !(bool)p.GetValue(o))
            Console.WriteLine("awesome!");
    }
}
12
glennkentwell

Die akzeptierte Antwort beschreibt richtig, wie die Liste deklariert werden sollte und wird für die meisten Szenarien dringend empfohlen.

Ich bin jedoch auf ein anderes Szenario gestoßen, das auch die Frage abdeckt. Was ist, wenn Sie eine vorhandene Objektliste verwenden müssen, z. B. ViewData["htmlAttributes"] in MVC? Wie können Sie auf seine Eigenschaften zugreifen (sie werden normalerweise über new { @style="width: 100px", ... } erstellt)?

Für dieses etwas andere Szenario möchte ich Ihnen mitteilen, was ich herausgefunden habe. In den folgenden Lösungen gehe ich von der folgenden Erklärung für nodes aus:

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 dynamisieren und schreiben:

if (nodes.Any(n => ((dynamic)n).Checked == false))
    Console.WriteLine("found not checked element!");

Note: Hierbei wird Late Binding verwendet. Dies bedeutet, dass es nur zur Laufzeit erkannt wird, wenn das Objekt keine Checked -Eigenschaft hat und in diesem Fall eine RuntimeBinderException ausgelöst wird. Wenn Sie also versuchen, eine nicht vorhandene Checked2-Eigenschaft zu verwenden Sie erhalten zur Laufzeit folgende Meldung: "'<>f__AnonymousType0<bool,int,string>' does not contain a definition for 'Checked2'".

2. Lösung mit Reflexion

Hintergrund

Als Ausgangspunkt fand ich eine gute Antwort hier . Die Idee ist, den anonymen Datentyp mithilfe von Reflektion in ein Wörterbuch zu konvertieren.

Inspiriert durch den Code im obigen Link habe ich eine Erweiterungsklasse erstellt, die den Zugriff auf anonyme Eigenschaften vereinfacht. Mit dieser Klasse können Sie die Abfrage einfach wie folgt durchführen:

if (nodes.AccessListItems().Any(n => (bool)n["Checked"] == false))
{
    Console.WriteLine("found not checked element!");
}

Sie müssen lediglich die folgende Erweiterungsklasse hinzufügen:

// simplifies access to anonymous properties
public static class AnonymousTypeExtensions
{
    // make properties of object accessible 
    // eg. x.AccessProperties() or x.AccessProperties()["PropName"]
    public static IDictionary AccessProperties(this object o, string propertyName=null)
    {
        Type type = o?.GetType();
        var properties = type?.GetProperties()
        ?.Select(n => n.Name)
        ?.ToDictionary(k => k, k => type.GetProperty(k).GetValue(o, null));
        return properties;
    }

    // returns specific property, i.e. x.AccessProperty(propertyName)
    public static object AccessProperty(this object o, string propertyName)
    {
        return o?.AccessProperties()?[propertyName];
    }

    // converts object list into list of properties
    public static List<IDictionary> AccessListItems(this List<object> objectList)
    {
        var accessibleList = new List<IDictionary>();
        foreach (object obj in objectList)
        {
            accessibleList.Add(obj.AccessProperties());
        }
        return accessibleList;
    }   
}

Der obige Code verwendet die seit C # Version 6.0 verfügbaren Operatoren null-conditional . Wenn Sie mit älteren Compilern arbeiten, ersetzen Sie einfach ?. durch . und ?[ durch [. Behalten Sie es andernfalls bei, da die Handhabung von Nullen wesentlich vereinfacht wird.

Hinweis: Wie bei der anderen Lösung mit Dynamic wird auch diese Lösung mit Late Binding verwendet. In diesem Fall wird jedoch keine Ausnahme angezeigt. Das Element wird einfach nicht gefunden, wenn Sie auf eine nicht vorhandene Eigenschaft verweisen . Für einige Anwendungen kann es nützlich sein, dass die Eigenschaft über eine Zeichenfolge referenziert wird.

0
Matt

Vor kurzem hatte ich das gleiche Problem in .NET 3.5 (keine Dynamik verfügbar). So löste ich:

// pass anonymous object as argument
var args = new { Title = "Find", Type = typeof(FindCondition) };

using (frmFind f = new frmFind(args)) 
{
...
...
}

Von irgendwo auf Stackoverflow angepasst:

// Use a custom cast extension
public static T CastTo<T>(this Object x, T targetType)
{
   return (T)x;
}

Holen Sie sich das Objekt jetzt per Cast zurück:

public partial class frmFind: Form
{
    public frmFind(object arguments)
    {

        InitializeComponent();

        var args = arguments.CastTo(new { Title = "", Type = typeof(Nullable) });

        this.Text = args.Title;

        ...
    }
    ...
}
0
orfruit