2015-04-02 15 views
18

Her anahtar için bir özelliği bir anonim türe dönüştürmeye çalışıyorum.C# sözlüğe özellik içeren anonim nesneyi

Google'ı denedim ancak bulabildiğim tek şey, anonim bir nesneyi bir sözlüğe nasıl dönüştüreceğiydi.

Benim Sözlük şuna benzer:

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

Ve şöyle bir anonim nesne dönmek istiyorum.

var o = new 
{ 
    Id = "1", 
    Title = "My title", 
    Description = "Blah blah blah" 
}; 

yüzden sözlükte her KeyValuePair aracılığıyla döngü de öyle ve her anahtar için nesnenin bir özelliği yaratacak.

Nereden başlayacağımı bilmiyorum.

Lütfen

Yardım edin.

+7

Anonim nesneyi ne için kullanıyorsunuz? C# javascript değil. – ryanyuyu

+1

Bunun mümkün olduğundan emin değilim, çünkü burada sunduğunuz nesne derleme zamanında bir sınıfa oluşturulur, böylece özellikleri çalışma zamanında oluşturamazsınız. –

+1

Anonim bir yazı türü dinamik bir tür değil: http://stackoverflow.com/questions/391529/anonymous-type-vs-dynamic-type – Martijn

cevap

25

Temelde yapamazsınız. Anonim türler derleyici tarafından yaratılır, bu nedenle derlemenizde, onlara verilen tüm isimlerle birlikte bulunurlar. (Bu örnekte tür özelliği sorun değil, uygulama ayrıntısı olarak derleyici, genel bir tür oluşturur ve sonra uygun türde bağımsız değişkenler kullanarak bunun bir örneğini oluşturur.)

Bir tür için soruyorsunuz yürütme zamanında belirlenen özelliklerle - bu yalnızca anonim türlerin nasıl çalıştığına uymuyor. Temelde, derleme zamanında kullanarak kod derlemeniz gerekirdi - ki bu daha sonra farklı bir mecliste olduğu gibi bir acı olur ve anonim tipler dahili ...

Belki de bunun yerine ExpandoObject'u kullanmalısınız? Daha sonra dynamic kullanarak her şey normal olarak özelliklerine erişebilecek. İşte

+2

Dinamik olarak yansıma yoluyla yeni bir tür oluşturabilir. Ben * diyemeyiz * bu yararlı veya akıllı olurdu ... Bir XY sorunu gibi görünüyor – xanatos

+1

@ xanatos Dinamik olarak yeni bir anonim tip oluşturamıyor olabilir. Derleyici tarafından derleme zamanında oluşturulmalıdır. Evet XY problemi gibi kokuyor. –

+1

@SriramSakthivel "Anonim" kavramı basitçe "C# kodunda yazmazsınız ve derleyici onu komik bir ad ve bazı özniteliklerle üretir" ... O kesinlikle yeni bir tür yaratabilir, komik olsun isim ve bazı öznitelikler ... Teknik olarak bu anonim bir tür olmayacak, ancak fark minimum – xanatos

2

bir ExpandoObject (this post yardımıyla) Temelde

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

var expando = new ExpandoObject() as IDictionary<string, Object>; 
foreach(var kvp in dict) 
    expando.Add(kvp.Key, kvp.Value); 
3

olarak yapabileceğini nasıl ki sen trivially yapabileceği bir şey değildir; anonim tipler hala sahnelerin arkasındaki tüm normal kodlara sahiptir: sadece onu görmüyorsunuz. Ne yapabildiğiniz dynamic ile aynı şeydir, ancak bu yansıma vb. Bekleyen API'lar için işe yaramaz. Bu nedenle, anahtar yoluyla erişmeniz gerektiğinden, çoğu kod sözlüğüne erişim, bir koddan daha uygun olacaktır. anonim tip veya dynamic türü.

1

Bu anonim bir nesne değil, ancak bunu bir DynamicObject ile başarabilirsiniz! Aşağıdakileri yapabilirsin.

public class MyExpando : DynamicObject 
{ 
    Dictionary<string, object> dictionary; 
    public MyExpando() 
    { 
     dictionary = new Dictionary<string, object> 
     { 
      {"Id", "1"}, 
      {"Title", "My title"}, 
      {"Description", "Blah blah blah"}, 
     }; 
    } 

    public override bool TryGetMember(GetMemberBinder binder, out object result) 
    { 
     return dictionary.TryGetValue(binder.Name, out result); 
    } 

    public override bool TrySetMember(SetMemberBinder binder, object value) 
    { 
     if (!dictionary.ContainsKey(binder.Name)) 
      return false; 
     dictionary[binder.Name] = value; 
     return true; 
    } 
} 

Ardından nesneyi istediğiniz özelliklere sahip olacaksınız. Tabii

dynamic o = new MyExpando(); 
Console.WriteLine("Id : " + o.Id + ", Title : " + o.Title + ", Description : " + o.Description); 

Olumsuz üyesi ya derleme zamanında olup olmadığını görmek için derleme zamanında ve hiçbir check kontrol hiçbir türü olmasıdır.

9

Şimdi, en az ayda bir kez, çalışma zamanında anonim bir türün nasıl oluşturulacağını soruyor ...İşte yanıttır:

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

Bu büyük, şişman, zamanında ancak (hatta C# yasadışı karakterleri kullanabilirsiniz) istediğiniz adlandırılan özelliklere sahip bazı sınıfları oluşturmak için Reflection.Emit kullanacağı kod bloğu. Bu sınıflar, C# derleyicisi 12.0.31101.0 tarafından oluşturulan anonim sınıfların adlandırma kurallarını izleyecektir. IL seviyesinde bile neredeyse eşit olmalıdırlar. Tüm Equals(), , ve ToString() tüm C# derleyicisi 12.0.31101.0 tarafından uygulandığı gibi uygulanır, tüm alanlar aynı ada sahip, CompilerGeneratedAttribute eklenmiştir (bu ahlaki yanlış, biliyorum :-)) vb. Bu yüzden sınıflar walk like an anonymous duck'u yarattılar ve anonim bir ördek gibi kaçarlar ... Onlar pratik olarak anonim ördeklerdir :-) (Roslyn ördeklerinin farklı bir alt tür olduğunu fark ettiler ... Onların tüyleri biraz farklı ... anonim bir ördek doğurucu olabilir kolayca iki alt türü ayırt eder :-))

Şimdi, cui prodest?'a sormak isterseniz Oluşturulan sınıflar yalnızca yansıma yoluyla kullanılabilir, bu yüzden kullanımı zor, ancak belirli bir kullanım durumu vardır, Marc Gravell individuated: .NET çerçevesinin, nesneleri (örneğin, tüm çeşitli datagrids) oluşturması için yansımayı yoğun olarak kullanan kısımları vardır. Bu parçalar, dynamic nesnelerle uyumsuzdur ve çoğu zaman object[]'u desteklemez. Bir çözüm DataTable yılında verilerini kapsamak için genellikle ... ya sen bu yöntemi kullanabilirsiniz özel durumda bu :-)

kullanabilirsiniz: Böyle

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

:

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

object obj1 = FromDictToAnonymousObj(dict); 

.

+0

olurdu .Linq.Dynamic.Core/blob/master/src/System.Linq.Dynamic.Core/DynamicClassFactory.cs –

+2

güncellenmiş sürümü https://github.com/StefH/System bulunabilir kabul edilmelidir doğru :) –

+0

Güzel, ama daha sınırlı bir sürüm yaptım, ancak derleyici gibi eşleme türlerini birleştirmesini isterdim. – NetMage

İlgili konular