14 Stimmen

Wie kann man einem anonymen Objekt dynamisch Eigenschaften hinzufügen?

Mögliches Duplikat:
Ist es möglich, einen anonymen Typ in C# mit einer variablen/dynamischen Menge von Feldern zu deklarieren?

Ich habe einen Query Builder erstellt, der eine Abfrage konstruiert, indem er einige GET-Werte prüft, die der Benutzer in meiner ASP.NET MVC3-Anwendung festgelegt hat. Dieser Query Builder kann Sortierung, Begrenzung und Filterung (die WHERE-Klausel) hinzufügen und gibt dann die konstruierte Abfrage zurück.

Diese Abfrage geht dann an mein Dapper-Repository, das versucht, die Abfrage mit auszuführen:

using (IDbConnection connection = new MySqlConnection(ConnectionStringFactory.GetConnectionString(Database.Push)))
{
    connection.Open();

    return connection.Query<Notification>(query.QueryString,
                                          new 
                                          {
                                              someAnonymousStuffHere = SomeValue
                                          });
}

Die Parameter für die Abfrage (es handelt sich um eine vorbereitete Anweisung) müssen jedoch in einem anonymen Typ abgelegt werden. Das Problem ist, dass ich nicht weiß, wie ich diesen anonymen Typ dynamisch konstruieren kann. Was ich jetzt mache, ist, alle Parameter in ein Dictionary<string, string> im Query Builder zu schieben, wobei der Schlüssel der Name der Eigenschaft ist und der Wert, nun ja, der Wert ist.

Ich kann nicht einfach einen anonymen Typ in meinem Query Builder definieren, weil der Builder aus mehreren Schritten besteht, von denen einige nicht ausgeführt werden. So haben wir manchmal 5 Parameter, manchmal 3 Parameter, usw.

Ich hoffe, ich habe mein Problem klar genug erklärt.

24voto

Martin Liversage Punkte 100306

Anonyme Typen sind einfach ein Komfort, bei dem der Compiler einen Typ für Sie "on the fly" erstellen kann, um Ihnen einige Tipparbeit zu ersparen. Er ist jedoch immer noch statisch typisiert. Wenn Sie einen "intelligenteren" Typ mit mehr Funktionalität benötigen, als Sie von einem anonymen Typ erhalten, oder wenn Sie Instanzen des Typs weitergeben müssen, müssen Sie einen "echten" Typ erstellen, wie Sie es vor der Existenz anonymer Typen getan hätten.

Eine weitere Möglichkeit ist die Verwendung der dynamic Merkmal. Sie können einen dynamischen Typ erstellen, indem Sie zum Beispiel ExpandoObject . Hier ist ein kleines Beispiel, wie Sie es verwenden können:

dynamic expando = new ExpandoObject();
expando.Name = "Martin";
if (((IDictionary<String, Object>) expando).ContainsKey("Name"))
  Console.WriteLine(expando.Name);

Das Expando ist eigentlich ein verherrlichtes Wörterbuch, und die Verwendung eines Wörterbuchs (wie Sie es tun) könnte sich als die bessere Lösung erweisen.

5voto

asawyer Punkte 17240

Anonyme Typen sind zur Kompilierzeit noch statisch typisiert. Ich würde vorschlagen, sich die dynamic Sprachfunktionen, oder Sie bleiben bei Ihrem Wörterbuch.

Hier ein Beispiel für das Laden eines dynamischen Objekts aus einem Wörterbuch mit Schlüsseln/Werten und den anschließenden Zugriff darauf, als wäre es ein statisch typisiertes Objekt.

//linqpad
void Main()
{
    IDictionary<string,object> items = new Dictionary<string,object>();
    items.Add("test","123");

    dynamic props = DynamicProperties.LoadFromDictionary(items);

    string item = props.test;

    item.Dump();
}

public class DynamicProperties : DynamicObject
{
    private DynamicProperties(){}

    private Dictionary<string, object> dictionary = new Dictionary<string, object>();

    public static DynamicProperties LoadFromDictionary(IDictionary<string,object> Dictionary)
    {
        dynamic dprop = new DynamicProperties();
        foreach(var item in Dictionary)
        {
            dprop.dictionary.Add(item.Key.ToLower(),item.Value);
        }
        return dprop;
    }
    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        string name = binder.Name.ToLower();
        Console.WriteLine("Trying to get " + name);
        return this.dictionary.TryGetValue(name,out result);
    }
    public override bool TrySetMember(SetMemberBinder binder, object value)
    {
        Console.WriteLine("TrySetMember: " + value.ToString());
        this.dictionary[binder.Name.ToLower()] = value;
        return true;
    }
}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X