Wörterbuch <Zeichenfolge, Objekt> in anonymes Objekt konvertieren?


81

Um die Dinge klarer zu machen, erkläre ich zunächst mein Szenario von oben:

Ich habe eine Methode mit der folgenden Signatur:

public virtual void SendEmail(String from, List<String> recepients, Object model)

Ich möchte ein anonymes Objekt generieren, das neben den ersten beiden Parametern auch die Eigenschaften des Modellobjekts aufweist. Das Reduzieren des Modellobjekts in eine PropertyInfo [] ist sehr einfach. Dementsprechend dachte ich daran, ein Wörterbuch zu erstellen, das die PropertyInfos und die ersten beiden Parameter enthält und dann in das anonyme Objekt konvertiert wird, wobei der Schlüssel der Name der Eigenschaft und der Wert der tatsächliche Wert der Eigenschaft ist.

Ist das möglich? Irgendwelche anderen Vorschläge?


Was ist der Grund, warum Sie dies tun möchten?
Mattias Jakobsson

1
Ich bezweifle, dass Sie einen beliebigen Satz von Schlüsselwerten problemlos unterstützen können - Sie müssten zur Laufzeit dynamisch einen neuen Typ mit diesen Eigenschaften erstellen. Da Sie sie erst dann zurücklesen, sollten Sie eine Überladung erstellen, die auch Ihr Wörterbuch akzeptiert.
Rup

@ Rup: ​​Eigentlich ist das auch eine vernünftige Alternative. Ich habe bereits eine Verknüpfung gefunden, die gut zu meinen Anforderungen passt, aber ich würde immer noch gerne die Antwort auf meine Frage oben wissen ... nur aus Neugier :)
Kassem

Überprüfen Sie die folgenden Links, sehr gute Lösung für die Konvertierung von Wörterbuch in anonymen Typ: jacobcarpenter.wordpress.com/2008/03/13/… tomsundev.wordpress.com/2011/07/20/…
Mrinal Kamboj

Antworten:


116

Wenn Sie das Wörterbuch wirklich in ein Objekt konvertieren möchten, dessen Elemente die Elemente des Wörterbuchs enthalten, können Sie Folgendes verwenden ExpandoObject:

var dict = new Dictionary<string, object> { { "Property", "foo" } };
var eo = new ExpandoObject();
var eoColl = (ICollection<KeyValuePair<string, object>>)eo;

foreach (var kvp in dict)
{
    eoColl.Add(kvp);
}

dynamic eoDynamic = eo;

string value = eoDynamic.Property;

Aber ich bin mir nicht sicher, wie dir das helfen wird.


1
+1 Aber ich bin mir nicht sicher, wie dir das helfen wird.
RyanMAd

Wie mache ich dasselbe in vb.net?
Mojtaba Rezaeian

3
In der Frage, warum Sie das jemals tun würden. Wenn Sie ein Modell an eine Razor-Vorlage übergeben, ist es einfacher, mit einem dynamischen Objekt als mit einem Wörterbuch zu arbeiten. Wenn Sie also ein Wörterbuch haben, möchten Sie es in ein dynamisches Objekt konvertieren. In Ihrer * .cshtml-Vorlage sehen Platzhalter dann folgendermaßen aus: @ Model.Name, statt: @Model ["Name"].
Dalenewman

Randnotiz: Funktioniert ExpandoObjectnicht mit Reflexion, da es sich nicht um ein reales Objekt handelt. Wenn Sie also das Ergebnis an etwas übergeben, für das ein reflektiertes Objekt erforderlich ist, wird das Problem nicht gelöst. Ihre Optionen scheinen eine ausgefallene dynamische Typerstellung zu sein (möglicherweise benohead.com/blog/2013/12/26/… ) oder ... eine neue API zu finden / entwickeln, für die kein Objekt erforderlich ist, über das reflektiert werden kann.
Bambams

24

Ich habe versucht, dies in einer Anweisung mit einer Reduktionsfunktion (Aggregate in Linq) zu tun. Der folgende Code entspricht der akzeptierten Antwort:

var dict = new Dictionary<string, object> { { "Property", "foo" } };
dynamic eo = dict.Aggregate(new ExpandoObject() as IDictionary<string, Object>,
                            (a, p) => { a.Add(p.Key, p.Value); return a; });
string value = eo.Property;

10

Wenn Sie eine Klasse haben, die Sie auch im Wörterbuch verdecken möchten, können Sie ein Wörterbuch wie folgt in ein Objekt dieser Klasse konvertieren:

Beispielklasse:

public class Properties1
{
    public string Property { get; set; }
}

Die Lösung:

JavaScriptSerializer serializer = new JavaScriptSerializer();
Dictionary<string, object> dict = new Dictionary<string, object> { { "Property", "foo" } };
Properties1 properties = serializer.ConvertToType<Properties1>(dict);
string value = properties.Property;

Sie können auch eine solche Methode verwenden, um das Objekt aus dem Wörterbuch zu erstellen. Dazu müssen Sie natürlich auch eine Klasse haben.

private static T DictionaryToObject<T>(IDictionary<string, object> dict) where T : new()
{
    T t = new T();
    PropertyInfo[] properties = t.GetType().GetProperties();

    foreach (PropertyInfo property in properties)
    {
        if (!dict.Any(x => x.Key.Equals(property.Name, 
            StringComparison.InvariantCultureIgnoreCase)))
            continue;
        KeyValuePair<string, object> item = dict.First(x => x.Key.Equals(property.Name,
            StringComparison.InvariantCultureIgnoreCase));
        Type tPropertyType = t.GetType().GetProperty(property.Name).PropertyType;
        Type newT = Nullable.GetUnderlyingType(tPropertyType) ?? tPropertyType;
        object newA = Convert.ChangeType(item.Value, newT);
        t.GetType().GetProperty(property.Name).SetValue(t, newA, null);
    }
    return t;
}

Wenn Sie jedoch nicht über die Klasse verfügen, können Sie ein dynamisches Objekt aus einem Wörterbuch wie dem folgenden erstellen:

private static dynamic DictionaryToObject(Dictionary<string, object> dict)
{
    IDictionary<string, object> eo = (IDictionary<string, object>)new ExpandoObject();
    foreach (KeyValuePair<string, object> kvp in dict)
    {
        eo.Add(kvp);
    }
    return eo;
}

Sie können es so verwenden:

Dictionary<string, object> dict = new Dictionary<string, object> {{ "Property", "foo" }};
dynamic properties = DictionaryToObject(dict);
string value = properties.Property;

6

Wenn Sie Dictionary<string, object>zu Anonym konvertieren möchten System.Object. Sie können diese Methode verwenden:

public static object FromDictToAnonymousObj<TValue>(IDictionary<string, TValue> dict)
{
    var types = new Type[dict.Count];

    for (int i = 0; i < types.Length; i++)
    {
        types[i] = typeof(TValue);
    }

    // dictionaries don't have an order, so we force an order based
    // on the Key
    var ordered = dict.OrderBy(x => x.Key).ToArray();

    string[] names = Array.ConvertAll(ordered, x => x.Key);

    Type type = AnonymousType.CreateType(types, names);

    object[] values = Array.ConvertAll(ordered, x => (object)x.Value);

    object obj = type.GetConstructor(types).Invoke(values);

    return obj;
}

so was:

var dict = new Dictionary<string, string>
{
    {"Id", "1"},
    {"Title", "My title"},
    {"Description", "Blah blah blah"},
};

object obj1 = FromDictToAnonymousObj(dict);

um Ihr Objekt zu erhalten. Wo AnonymousTypeKlassencode ist:

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;

/// <summary>
/// The code generated should be nearly equal to the one generated by
/// csc 12.0.31101.0 when compiling with /optimize+ /debug-. The main
/// difference is in the GetHashCode() (the base init_hash used is 
/// compiler-dependant) and in the maxstack of the generated methods.
/// Note that Roslyn (at least the one present at 
/// tryroslyn.azurewebsites.net) generates different code for anonymous
/// types.
/// </summary>
public static class AnonymousType
{
    private static readonly ConcurrentDictionary<string, Type> GeneratedTypes = new ConcurrentDictionary<string, Type>();

    private static readonly AssemblyBuilder AssemblyBuilder;
    private static readonly ModuleBuilder ModuleBuilder;
    private static readonly string FileName;

    // Some objects we cache
    private static readonly CustomAttributeBuilder CompilerGeneratedAttributeBuilder = new CustomAttributeBuilder(typeof(CompilerGeneratedAttribute).GetConstructor(Type.EmptyTypes), new object[0]);
    private static readonly CustomAttributeBuilder DebuggerBrowsableAttributeBuilder = new CustomAttributeBuilder(typeof(DebuggerBrowsableAttribute).GetConstructor(new[] { typeof(DebuggerBrowsableState) }), new object[] { DebuggerBrowsableState.Never });
    private static readonly CustomAttributeBuilder DebuggerHiddenAttributeBuilder = new CustomAttributeBuilder(typeof(DebuggerHiddenAttribute).GetConstructor(Type.EmptyTypes), new object[0]);

    private static readonly ConstructorInfo ObjectCtor = typeof(object).GetConstructor(Type.EmptyTypes);
    private static readonly MethodInfo ObjectToString = typeof(object).GetMethod("ToString", BindingFlags.Instance | BindingFlags.Public, null, Type.EmptyTypes, null);

    private static readonly ConstructorInfo StringBuilderCtor = typeof(StringBuilder).GetConstructor(Type.EmptyTypes);
    private static readonly MethodInfo StringBuilderAppendString = typeof(StringBuilder).GetMethod("Append", BindingFlags.Instance | BindingFlags.Public, null, new[] { typeof(string) }, null);
    private static readonly MethodInfo StringBuilderAppendObject = typeof(StringBuilder).GetMethod("Append", BindingFlags.Instance | BindingFlags.Public, null, new[] { typeof(object) }, null);

    private static readonly Type EqualityComparer = typeof(EqualityComparer<>);
    private static readonly Type EqualityComparerGenericArgument = EqualityComparer.GetGenericArguments()[0];
    private static readonly MethodInfo EqualityComparerDefault = EqualityComparer.GetMethod("get_Default", BindingFlags.Static | BindingFlags.Public, null, Type.EmptyTypes, null);
    private static readonly MethodInfo EqualityComparerEquals = EqualityComparer.GetMethod("Equals", BindingFlags.Instance | BindingFlags.Public, null, new[] { EqualityComparerGenericArgument, EqualityComparerGenericArgument }, null);
    private static readonly MethodInfo EqualityComparerGetHashCode = EqualityComparer.GetMethod("GetHashCode", BindingFlags.Instance | BindingFlags.Public, null, new[] { EqualityComparerGenericArgument }, null);

    private static int Index = -1;

    static AnonymousType()
    {
        var assemblyName = new AssemblyName("AnonymousTypes");

        FileName = assemblyName.Name + ".dll";

        AssemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave);
        ModuleBuilder = AssemblyBuilder.DefineDynamicModule("AnonymousTypes", FileName);
    }

    public static void Dump()
    {
        AssemblyBuilder.Save(FileName);
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="types"></param>
    /// <param name="names"></param>
    /// <returns></returns>
    public static Type CreateType(Type[] types, string[] names)
    {
        if (types == null)
        {
            throw new ArgumentNullException("types");
        }

        if (names == null)
        {
            throw new ArgumentNullException("names");
        }

        if (types.Length != names.Length)
        {
            throw new ArgumentException("names");
        }

        // Anonymous classes are generics based. The generic classes
        // are distinguished by number of parameters and name of 
        // parameters. The specific types of the parameters are the 
        // generic arguments. We recreate this by creating a fullName
        // composed of all the property names, separated by a "|"
        string fullName = string.Join("|", names.Select(x => Escape(x)));

        Type type;

        if (!GeneratedTypes.TryGetValue(fullName, out type))
        {
            // We create only a single class at a time, through this lock
            // Note that this is a variant of the double-checked locking.
            // It is safe because we are using a thread safe class.
            lock (GeneratedTypes)
            {
                if (!GeneratedTypes.TryGetValue(fullName, out type))
                {
                    int index = Interlocked.Increment(ref Index);

                    string name = names.Length != 0 ? string.Format("<>f__AnonymousType{0}`{1}", index, names.Length) : string.Format("<>f__AnonymousType{0}", index);
                    TypeBuilder tb = ModuleBuilder.DefineType(name, TypeAttributes.AnsiClass | TypeAttributes.Class | TypeAttributes.AutoLayout | TypeAttributes.NotPublic | TypeAttributes.Sealed | TypeAttributes.BeforeFieldInit);
                    tb.SetCustomAttribute(CompilerGeneratedAttributeBuilder);

                    GenericTypeParameterBuilder[] generics = null;

                    if (names.Length != 0)
                    {
                        string[] genericNames = Array.ConvertAll(names, x => string.Format("<{0}>j__TPar", x));
                        generics = tb.DefineGenericParameters(genericNames);
                    }
                    else
                    {
                        generics = new GenericTypeParameterBuilder[0];
                    }

                    // .ctor
                    ConstructorBuilder constructor = tb.DefineConstructor(MethodAttributes.Public | MethodAttributes.HideBySig, CallingConventions.HasThis, generics);
                    constructor.SetCustomAttribute(DebuggerHiddenAttributeBuilder);
                    ILGenerator ilgeneratorConstructor = constructor.GetILGenerator();
                    ilgeneratorConstructor.Emit(OpCodes.Ldarg_0);
                    ilgeneratorConstructor.Emit(OpCodes.Call, ObjectCtor);

                    var fields = new FieldBuilder[names.Length];

                    // There are two for cycles because we want to have
                    // all the getter methods before all the other 
                    // methods
                    for (int i = 0; i < names.Length; i++)
                    {
                        // field
                        fields[i] = tb.DefineField(string.Format("<{0}>i__Field", names[i]), generics[i], FieldAttributes.Private | FieldAttributes.InitOnly);
                        fields[i].SetCustomAttribute(DebuggerBrowsableAttributeBuilder);

                        // .ctor
                        constructor.DefineParameter(i + 1, ParameterAttributes.None, names[i]);
                        ilgeneratorConstructor.Emit(OpCodes.Ldarg_0);

                        if (i == 0)
                        {
                            ilgeneratorConstructor.Emit(OpCodes.Ldarg_1);
                        }
                        else if (i == 1)
                        {
                            ilgeneratorConstructor.Emit(OpCodes.Ldarg_2);
                        }
                        else if (i == 2)
                        {
                            ilgeneratorConstructor.Emit(OpCodes.Ldarg_3);
                        }
                        else if (i < 255)
                        {
                            ilgeneratorConstructor.Emit(OpCodes.Ldarg_S, (byte)(i + 1));
                        }
                        else
                        {
                            // Ldarg uses a ushort, but the Emit only
                            // accepts short, so we use a unchecked(...),
                            // cast to short and let the CLR interpret it
                            // as ushort
                            ilgeneratorConstructor.Emit(OpCodes.Ldarg, unchecked((short)(i + 1)));
                        }

                        ilgeneratorConstructor.Emit(OpCodes.Stfld, fields[i]);

                        // getter
                        MethodBuilder getter = tb.DefineMethod(string.Format("get_{0}", names[i]), MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName, CallingConventions.HasThis, generics[i], Type.EmptyTypes);
                        ILGenerator ilgeneratorGetter = getter.GetILGenerator();
                        ilgeneratorGetter.Emit(OpCodes.Ldarg_0);
                        ilgeneratorGetter.Emit(OpCodes.Ldfld, fields[i]);
                        ilgeneratorGetter.Emit(OpCodes.Ret);

                        PropertyBuilder property = tb.DefineProperty(names[i], PropertyAttributes.None, CallingConventions.HasThis, generics[i], Type.EmptyTypes);
                        property.SetGetMethod(getter);
                    }

                    // ToString()
                    MethodBuilder toString = tb.DefineMethod("ToString", MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig, CallingConventions.HasThis, typeof(string), Type.EmptyTypes);
                    toString.SetCustomAttribute(DebuggerHiddenAttributeBuilder);
                    ILGenerator ilgeneratorToString = toString.GetILGenerator();

                    ilgeneratorToString.DeclareLocal(typeof(StringBuilder));

                    ilgeneratorToString.Emit(OpCodes.Newobj, StringBuilderCtor);
                    ilgeneratorToString.Emit(OpCodes.Stloc_0);

                    // Equals
                    MethodBuilder equals = tb.DefineMethod("Equals", MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig, CallingConventions.HasThis, typeof(bool), new[] { typeof(object) });
                    equals.SetCustomAttribute(DebuggerHiddenAttributeBuilder);
                    equals.DefineParameter(1, ParameterAttributes.None, "value");
                    ILGenerator ilgeneratorEquals = equals.GetILGenerator();
                    ilgeneratorEquals.DeclareLocal(tb);

                    ilgeneratorEquals.Emit(OpCodes.Ldarg_1);
                    ilgeneratorEquals.Emit(OpCodes.Isinst, tb);
                    ilgeneratorEquals.Emit(OpCodes.Stloc_0);
                    ilgeneratorEquals.Emit(OpCodes.Ldloc_0);

                    Label equalsLabel = ilgeneratorEquals.DefineLabel();

                    // GetHashCode()
                    MethodBuilder getHashCode = tb.DefineMethod("GetHashCode", MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig, CallingConventions.HasThis, typeof(int), Type.EmptyTypes);
                    getHashCode.SetCustomAttribute(DebuggerHiddenAttributeBuilder);
                    ILGenerator ilgeneratorGetHashCode = getHashCode.GetILGenerator();
                    ilgeneratorGetHashCode.DeclareLocal(typeof(int));

                    if (names.Length == 0)
                    {
                        ilgeneratorGetHashCode.Emit(OpCodes.Ldc_I4_0);
                    }
                    else
                    {
                        // As done by Roslyn
                        // Note that initHash can vary, because
                        // string.GetHashCode() isn't "stable" for 
                        // different compilation of the code
                        int initHash = 0;

                        for (int i = 0; i < names.Length; i++)
                        {
                            initHash = unchecked(initHash * (-1521134295) + fields[i].Name.GetHashCode());
                        }

                        // Note that the CSC seems to generate a 
                        // different seed for every anonymous class
                        ilgeneratorGetHashCode.Emit(OpCodes.Ldc_I4, initHash);
                    }

                    for (int i = 0; i < names.Length; i++)
                    {
                        // Equals()
                        Type equalityComparerT = EqualityComparer.MakeGenericType(generics[i]);
                        MethodInfo equalityComparerTDefault = TypeBuilder.GetMethod(equalityComparerT, EqualityComparerDefault);
                        MethodInfo equalityComparerTEquals = TypeBuilder.GetMethod(equalityComparerT, EqualityComparerEquals);

                        ilgeneratorEquals.Emit(OpCodes.Brfalse_S, equalsLabel);
                        ilgeneratorEquals.Emit(OpCodes.Call, equalityComparerTDefault);
                        ilgeneratorEquals.Emit(OpCodes.Ldarg_0);
                        ilgeneratorEquals.Emit(OpCodes.Ldfld, fields[i]);
                        ilgeneratorEquals.Emit(OpCodes.Ldloc_0);
                        ilgeneratorEquals.Emit(OpCodes.Ldfld, fields[i]);
                        ilgeneratorEquals.Emit(OpCodes.Callvirt, equalityComparerTEquals);

                        // GetHashCode();
                        MethodInfo EqualityComparerTGetHashCode = TypeBuilder.GetMethod(equalityComparerT, EqualityComparerGetHashCode);

                        ilgeneratorGetHashCode.Emit(OpCodes.Stloc_0);
                        ilgeneratorGetHashCode.Emit(OpCodes.Ldc_I4, -1521134295);
                        ilgeneratorGetHashCode.Emit(OpCodes.Ldloc_0);
                        ilgeneratorGetHashCode.Emit(OpCodes.Mul);
                        ilgeneratorGetHashCode.Emit(OpCodes.Call, EqualityComparerDefault);
                        ilgeneratorGetHashCode.Emit(OpCodes.Ldarg_0);
                        ilgeneratorGetHashCode.Emit(OpCodes.Ldfld, fields[i]);
                        ilgeneratorGetHashCode.Emit(OpCodes.Callvirt, EqualityComparerGetHashCode);
                        ilgeneratorGetHashCode.Emit(OpCodes.Add);

                        // ToString()
                        ilgeneratorToString.Emit(OpCodes.Ldloc_0);
                        ilgeneratorToString.Emit(OpCodes.Ldstr, i == 0 ? string.Format("{{ {0} = ", names[i]) : string.Format(", {0} = ", names[i]));
                        ilgeneratorToString.Emit(OpCodes.Callvirt, StringBuilderAppendString);
                        ilgeneratorToString.Emit(OpCodes.Pop);
                        ilgeneratorToString.Emit(OpCodes.Ldloc_0);
                        ilgeneratorToString.Emit(OpCodes.Ldarg_0);
                        ilgeneratorToString.Emit(OpCodes.Ldfld, fields[i]);
                        ilgeneratorToString.Emit(OpCodes.Box, generics[i]);
                        ilgeneratorToString.Emit(OpCodes.Callvirt, StringBuilderAppendObject);
                        ilgeneratorToString.Emit(OpCodes.Pop);
                    }

                    // .ctor
                    ilgeneratorConstructor.Emit(OpCodes.Ret);

                    // Equals()
                    if (names.Length == 0)
                    {
                        ilgeneratorEquals.Emit(OpCodes.Ldnull);
                        ilgeneratorEquals.Emit(OpCodes.Ceq);
                        ilgeneratorEquals.Emit(OpCodes.Ldc_I4_0);
                        ilgeneratorEquals.Emit(OpCodes.Ceq);
                    }
                    else
                    {
                        ilgeneratorEquals.Emit(OpCodes.Ret);
                        ilgeneratorEquals.MarkLabel(equalsLabel);
                        ilgeneratorEquals.Emit(OpCodes.Ldc_I4_0);
                    }

                    ilgeneratorEquals.Emit(OpCodes.Ret);

                    // GetHashCode()
                    ilgeneratorGetHashCode.Emit(OpCodes.Stloc_0);
                    ilgeneratorGetHashCode.Emit(OpCodes.Ldloc_0);
                    ilgeneratorGetHashCode.Emit(OpCodes.Ret);

                    // ToString()
                    ilgeneratorToString.Emit(OpCodes.Ldloc_0);
                    ilgeneratorToString.Emit(OpCodes.Ldstr, names.Length == 0 ? "{ }" : " }");
                    ilgeneratorToString.Emit(OpCodes.Callvirt, StringBuilderAppendString);
                    ilgeneratorToString.Emit(OpCodes.Pop);
                    ilgeneratorToString.Emit(OpCodes.Ldloc_0);
                    ilgeneratorToString.Emit(OpCodes.Callvirt, ObjectToString);
                    ilgeneratorToString.Emit(OpCodes.Ret);

                    type = tb.CreateType();

                    type = GeneratedTypes.GetOrAdd(fullName, type);
                }
            }
        }

        if (types.Length != 0)
        {
            type = type.MakeGenericType(types);
        }

        return type;
    }

    private static string Escape(string str)
    {
        // We escape the \ with \\, so that we can safely escape the
        // "|" (that we use as a separator) with "\|"
        str = str.Replace(@"\", @"\\");
        str = str.Replace(@"|", @"\|");
        return str;
    }
}

Referenz: https://stackoverflow.com/a/29428640/2073920


Gibt es eine Implementierung von AnonymousType in Dotnet Core
Cruiser KID

@CruiserKID Ich kenne keine ähnliche Implementierung. Obwohl Sie anonyme Typen in .NET Core genauso erstellen und bearbeiten können wie in .NET
Abdul Rauf am

6

Etwas modularere Version von svicks Antwort mit ein paar Erweiterungsmethoden:

public static class Extensions
{
    public static void AddRange<T>(this ICollection<T> collection, IEnumerable<T> items)
    {
        foreach (var item in items)
        {
            collection.Add(item);
        }
    }

    public static dynamic ToDynamicObject(this IDictionary<string, object> source)
    {
        ICollection<KeyValuePair<string, object>> someObject = new ExpandoObject();
        someObject.AddRange(source);
        return someObject;
    }
}

1
Ich mag die Idee. Es gibt jedoch keine ICollection.AddRange. Sie müssen entweder AddRange mithilfe von Erweiterungen bereitstellen oder versuchen,source.ToList().ForEach(someObject.Add)
Nils

Hoppla, guter Fang! Ich bin so an meine Erweiterungsmethoden gewöhnt, dass ich sie für selbstverständlich halte. Aktualisiert die Antwort.
Geir Sagberg

3

Anonyme Objekte werden vom Compiler für Sie generiert. Sie können keine dynamisch erstellen. Auf der anderen Seite können Sie ein solches Objekt emittieren, aber ich denke wirklich nicht, dass dies eine gute Idee ist.

Vielleicht können Sie dynamische Objekte ausprobieren? Das Ergebnis ist ein Objekt mit allen Eigenschaften, die Sie benötigen.


1
Ja, ein dynamisches Objekt wäre perfekt. Möchten Sie ein Beispiel geben?
Kassem

1
Ich denke nicht, dass dies eine genaue Aussage ist. Sie können zur Laufzeit sogar echte CLR-Typen erstellen. Ich kann mir nicht vorstellen, warum Sie zur Laufzeit keinen anonymen Typ erstellen konnten.
Chris Marisic

3
@ ChrisMarisic Zitat aus der Antwort "Sie können ein solches Objekt emittieren". Sicher kannst du.
Mike Chaliy

5
Dies ist keine Antwort, sondern ein Kommentar.
JotaBe

@JotaBe, es ist eigentlich eine Antwort, die indirekt sagt: "Das kannst du nicht." Ich glaube, es ist eine falsche Antwort, aber trotzdem eine Antwort.
Theta-Fisch

1

Die Gutschrift hier geht an die akzeptierte Antwort. Dies wurde hinzugefügt, weil ich eine List <Dictionary <Zeichenfolge, Objekt >> in eine List <Dynamic> verwandeln wollte. Der Zweck besteht darin, Datensätze aus einer Datenbanktabelle abzurufen. Hier ist was ich getan habe.

    public static List<dynamic> ListDictionaryToListDynamic(List<Dictionary<string,object>> dbRecords)
    {
        var eRecords = new List<dynamic>();
        foreach (var record in dbRecords)
        {
            var eRecord = new ExpandoObject() as IDictionary<string, object>;
            foreach (var kvp in record)
            {
                eRecord.Add(kvp);
            }
            eRecords.Add(eRecord);
        }
        return eRecords;
    }
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.