Chuyển đổi Từ điển <chuỗi, đối tượng> sang Đối tượng ẩn danh?


81

Đầu tiên, và để làm cho mọi thứ rõ ràng hơn, tôi sẽ giải thích kịch bản của mình từ đầu:

Tôi có một phương thức có chữ ký sau:

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

Những gì tôi muốn làm là tạo một đối tượng ẩn danh có các thuộc tính của đối tượng mô hình cùng với hai tham số đầu tiên. Việc làm phẳng đối tượng mô hình thành một PropertyInfo [] rất đơn giản. Theo đó, tôi đã nghĩ đến việc tạo một Từ điển sẽ chứa PropertyInfo's và hai tham số đầu tiên, sau đó được chuyển đổi thành đối tượng ẩn danh trong đó khóa là tên của thuộc tính và giá trị là giá trị thực của thuộc tính.

Điều đó có thể không? Bất cứ một đề nghị nào khác?


Lý do bạn muốn làm điều này là gì?
Mattias Jakobsson

1
Tôi nghi ngờ bạn có thể dễ dàng hỗ trợ một bộ giá trị khóa tùy ý - bạn phải tạo động một kiểu mới với các thuộc tính đó tại thời điểm chạy. Vì bạn sẽ chỉ đọc lại chúng sau đó, bạn nên làm tốt hơn để tạo quá tải cũng chấp nhận từ điển của bạn.
Rup

@Rup: Trên thực tế, đó cũng là một sự thay thế hợp lý. Tôi đã tìm thấy một shortcut mà hoạt động tốt cho các yêu cầu của tôi, nhưng tôi sẽ vẫn như biết câu trả lời cho câu hỏi của tôi ở trên ... chỉ vì tò mò :)
Kassem

Kiểm tra các liên kết sau đây, giải pháp rất tốt cho từ điển để chuyển đổi loại vô danh: jacobcarpenter.wordpress.com/2008/03/13/... tomsundev.wordpress.com/2011/07/20/...
Mrinal Kamboj

Câu trả lời:


116

Nếu bạn thực sự muốn chuyển đổi từ điển thành một đối tượng có các mục của từ điển là thuộc tính, bạn có thể sử dụng 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;

Nhưng tôi không chắc làm thế nào để làm điều đó sẽ giúp bạn.


1
+1 Nhưng tôi không chắc làm thế nào để làm điều đó sẽ giúp bạn.
RyanMAd

Làm thế nào để làm điều tương tự trong vb.net?
Mojtaba Rezaeian

3
Về vấn đề tại sao bạn lại làm điều này. Khi bạn chuyển một mô hình sang mẫu Razor, bạn sẽ dễ dàng làm việc với một đối tượng động hơn là từ điển. Vì vậy, nếu bạn có một từ điển, bạn muốn chuyển nó thành một đối tượng động. Sau đó, trong mẫu * .cshtml của bạn, các vị trí trông giống như sau: @ Model.Name, thay vì sau: @Model ["Tên"].
dalenewman

Lưu ý phụ: ExpandoObjectkhông hoạt động với phản xạ vì nó không phải là một đối tượng thực, vì vậy nếu bạn tình cờ chuyển kết quả cho một thứ gì đó yêu cầu một đối tượng sẽ được phản ánh trên đó không giải quyết được vấn đề. Các tùy chọn của bạn dường như là tạo kiểu động ưa thích (có thể là benohead.com/blog/2013/12/26/… ) hoặc ... tìm / phát triển một API mới không yêu cầu đối tượng có thể được phản ánh.
bambams

24

Tôi đã cố gắng thực hiện điều này trong một câu lệnh với hàm giảm (Tổng hợp trong Linq). Đoạn mã dưới đây thực hiện tương tự như câu trả lời được chấp nhận:

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

Nếu bạn có một lớp mà bạn cũng muốn giấu từ điển, bạn có thể sử dụng cách sau để chuyển đổi một từ điển thành một đối tượng của lớp đó:

Lớp mẫu:

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

Giải pháp:

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

Bạn cũng có thể sử dụng một phương thức như thế này để xây dựng đối tượng từ từ điển, rõ ràng điều này cũng yêu cầu bạn phải có một lớp.

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;
}

Tuy nhiên, nếu bạn không có lớp, bạn có thể tạo một đối tượng động từ một từ điển như sau:

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;
}

Bạn có thể sử dụng nó như thế này:

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

6

Nếu bạn muốn chuyển đổi sang Dictionary<string, object>Anonymous System.Object. Bạn có thể sử dụng phương pháp này:

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;
}

như thế này:

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

object obj1 = FromDictToAnonymousObj(dict);

để có được đối tượng của bạn. AnonymousTypeMã lớp ở đâu :

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;
    }
}

Tham khảo: https://stackoverflow.com/a/29428640/2073920


Có bất kỳ triển khai nào của AnonymousType trong lõi dotnet không
Cruiser KID

@CruiserKID Tôi không biết về bất kỳ cách triển khai tương tự nào. Mặc dù bạn có thể tạo và thao tác các kiểu ẩn danh trong .NET Core giống như bạn có thể làm trong .NET
Abdul Rauf

6

Phiên bản câu trả lời của svick mô-đun hơn một chút, sử dụng một số phương pháp mở rộng:

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
Tôi thích ý tưởng. Tuy nhiên, không có ICollection.AddRange. Bạn sẽ phải cung cấp AddRange bằng cách sử dụng các tiện ích mở rộng hoặc thử sử dụngsource.ToList().ForEach(someObject.Add)
Nils

Rất tiếc, bắt tốt! Tôi đã quá quen với các phương pháp mở rộng của mình, tôi coi chúng là điều hiển nhiên. Sẽ cập nhật câu trả lời.
Geir Sagberg

3

Đối tượng ẩn danh là đối tượng được tạo cho bạn bởi trình biên dịch. Bạn không thể tạo động tạo một. Mặt khác, bạn có thể phát ra vật thể như vậy, nhưng tôi thực sự không nghĩ đây là ý kiến ​​hay.

Có thể bạn có thể thử các đối tượng động? Kết quả sẽ là một đối tượng với tất cả các thuộc tính bạn cần.


1
Đúng vậy, một đối tượng động sẽ hoàn hảo. Bạn muốn cung cấp một ví dụ?
Kassem

1
Tôi không nghĩ đây là một tuyên bố chính xác, bạn thậm chí có thể tạo các loại CLR thực sự trong thời gian chạy Tôi không thể tưởng tượng được tại sao bạn không thể tạo một loại ẩn danh trong thời gian chạy.
Chris Marisic

3
@ChrisMarisic trích dẫn từ câu trả lời "bạn có thể phát ra đối tượng như vậy". Chắc chắn bạn có thể.
Mike Chaliy

5
Đây không phải là một câu trả lời, mà là một bình luận.
JotaBe

@JotaBe, nó thực sự là một câu trả lời, nói một cách gián tiếp: "Bạn không thể làm điều đó." Tôi tin rằng đó là một câu trả lời không chính xác, nhưng tất cả đều giống nhau.
theta-fish

1

Tín dụng ở đây đi đến câu trả lời được chấp nhận. Thêm điều này vì tôi muốn biến Danh sách <Từ điển <chuỗi, đối tượng >> thành Danh sách <động>. Mục đích là để kéo các bản ghi từ một bảng cơ sở dữ liệu. Đây là những gì tôi đã làm.

    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;
    }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.