【问题标题】:How to dynamic new Anonymous Class?如何动态创建新的匿名类?
【发布时间】:2011-04-13 23:48:35
【问题描述】:

在 C# 3.0 中,您可以使用以下语法创建匿名类

var o1 = new { Id = 1, Name = "Foo" };

有没有办法将这些匿名类动态创建到变量中?


例子:

var o1 = new { Id = 1, Name = "Foo" };
var o2 = new { SQ = 2, Birth = DateTime.Now };

动态创建示例:

var o1 = DynamicNewAnonymous(new NameValuePair("Id", 1), new NameValuePair("Name", "Foo"));
var o2 = DynamicNewAnonymous(new NameValuePair("SQ", 2), new NameValuePair("Birth", 
DateTime.Now));

因为我需要做:

dynamic o1 = new ExpandObject(); 
o1."ID" = 1;    <--"ID" is dynamic name
o1."Name" = "Foo";  <--"Name" is dynamic name

场景1:

void ShowPropertiesValue(object o)
{
  Type oType = o.GetType();
  foreach(var pi in oType.GetProperties())
  {
    Console.WriteLine("{0}={1}", pi.Name, pi.GetValue(o, null));
  }
}

如果我打电话:

dynamic o1 = new ExpandObject();
o1.Name = "123";
ShowPropertiesValue(o1);

无法显示结果:

Name = 123

还有我如何将 ExpandoObject 转换为 AnonymouseType ?

Type type = o1.GetType();
type.GetProperties();   <--I hope it can get all property of o1

最后,我修改 ShowPropertiesValue() 方法

void ShowPropertiesValue(object o)
{
  if( o is static object ) <--How to check it is dynamic or static object?
  {
    Type oType = o.GetType();
    foreach(var pi in oType.GetProperties())
    {
      Console.WriteLine("{0}={1}", pi.Name, pi.GetValue(o, null));
    }
  }
  else if( o is dynamic object )  <--How to check it is dynamic or static object?
  {
    foreach(var pi in ??? )  <--How to get common dynamic object's properties info ?
    {
      Console.WriteLine("{0}={1}", pi.Name, pi.GetValue(o, null));
    } 
  }
}

如何实现 DynamicNewAnonymous 方法或如何修改 ShowPropertiesValue()?

我的动机是:

dynamic o1 = new MyDynamic();
o1.Name = "abc";
Type o1Type = o1.GetType();
var props = o1Type.GetProperties(); <--I hope can get the Name Property

如果我可以挂钩 dynamicObject 的 GetType 方法,并强制转换为强类型类型。 上面的无缝代码可以正常工作。

【问题讨论】:

  • ExpandoObject,而不是 ExpandObject(添加了 'o')。

标签: c# c#-3.0 anonymous-types


【解决方案1】:

匿名类型只是隐式声明的常规类型。它们与dynamic 关系不大。

现在,如果您要使用 ExpandoObject 并通过 dynamic 变量引用它,您可以即时添加或删除字段。

编辑

当然可以:只需将其转换为 IDictionary&lt;string, object&gt;。然后就可以使用索引器了。

您使用相同的转换技术来迭代字段:

dynamic employee = new ExpandoObject();
employee.Name = "John Smith";
employee.Age = 33;

foreach (var property in (IDictionary<string, object>)employee)
{
    Console.WriteLine(property.Key + ": " + property.Value);
}
// This code example produces the following output:
// Name: John Smith
// Age: 33

点击该链接可以找到以上代码及更多内容。

【讨论】:

  • 但是 ExpandoObject 做不到:dynamic o1 = new ExpandObject(); o1."ID" = 1; o1."Name" = "Foo";
  • 但也不能这样做:Type o1Type = o1.GetType(); var 道具 = o1Type.GetProperties();道具为空
  • 您所做的只是说动态属性与强类型属性不同。这是微不足道的事实。
  • stackoverflow.com/a/4024786/998793 展示了如何通过转换为通用字典来做到这一点:((IDictionary&lt;string, object&gt;)o1).Add("Name", "Foo");。然后您可以以o1.Name 身份访问
【解决方案2】:

你可以像这样创建一个 ExpandoObject:

IDictionary<string,object> expando = new ExpandoObject();
expando["Name"] = value;

在将其转换为动态后,这些值将看起来像属性:

dynamic d = expando;
Console.WriteLine(d.Name);

但是,它们不是实际属性,无法使用反射访问。所以下面的语句会返回一个null:

d.GetType().GetProperty("Name") 

【讨论】:

    【解决方案3】:

    当然可以使用非常酷的 ExpandoObject 类来创建动态类。 但最近我在项目上工作,并面临 Expando Object 在 xml 上的格式与简单的匿名类不同,很遗憾 =( ,这就是为什么我决定创建自己的类并与你分享。它正在使用反射和动态指令,真正动态地构建程序集、类和实例。您可以动态添加、删除和更改类中包含的属性 这里是:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Reflection;
    using System.Reflection.Emit;
    using static YourNamespace.DynamicTypeBuilderTest;
    
    namespace YourNamespace
    {
    
        /// This class builds Dynamic Anonymous Classes
    
        public class DynamicTypeBuilderTest
        {    
            ///   
            /// Create instance based on any Source class as example based on PersonalData
            ///
            public static object CreateAnonymousDynamicInstance(PersonalData personalData, Type dynamicType, List<ClassDescriptorKeyValue> classDescriptionList)
            {
                var obj = Activator.CreateInstance(dynamicType);
    
                var propInfos = dynamicType.GetProperties();
    
                classDescriptionList.ForEach(x => SetValueToProperty(obj, propInfos, personalData, x));
    
                return obj;
            }
    
            private static void SetValueToProperty(object obj, PropertyInfo[] propInfos, PersonalData aisMessage, ClassDescriptorKeyValue description)
            {
                propInfos.SingleOrDefault(x => x.Name == description.Name)?.SetValue(obj, description.ValueGetter(aisMessage), null);
            }
    
            public static dynamic CreateAnonymousDynamicType(string entityName, List<ClassDescriptorKeyValue> classDescriptionList)
            {
                AssemblyName asmName = new AssemblyName();
                asmName.Name = $"{entityName}Assembly";
                AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(asmName, AssemblyBuilderAccess.RunAndCollect);
    
                ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule($"{asmName.Name}Module");
    
                TypeBuilder typeBuilder = moduleBuilder.DefineType($"{entityName}Dynamic", TypeAttributes.Public);
    
                classDescriptionList.ForEach(x => CreateDynamicProperty(typeBuilder, x));
    
                return typeBuilder.CreateTypeInfo().AsType();
            }
    
            private static void CreateDynamicProperty(TypeBuilder typeBuilder, ClassDescriptorKeyValue description)
            {
                CreateDynamicProperty(typeBuilder, description.Name, description.Type);
            }
    
            ///
            ///Creation Dynamic property (from MSDN) with some Magic
            ///
            public static void CreateDynamicProperty(TypeBuilder typeBuilder, string name, Type propType)
            {
                FieldBuilder fieldBuider = typeBuilder.DefineField($"{name.ToLower()}Field",
                                                                propType,
                                                                FieldAttributes.Private);
    
                PropertyBuilder propertyBuilder = typeBuilder.DefineProperty(name,
                                                                 PropertyAttributes.HasDefault,
                                                                 propType,
                                                                 null);
    
                MethodAttributes getSetAttr =
                    MethodAttributes.Public | MethodAttributes.SpecialName |
                        MethodAttributes.HideBySig;
    
                MethodBuilder methodGetBuilder =
                    typeBuilder.DefineMethod($"get_{name}",
                                               getSetAttr,
                                               propType,
                                               Type.EmptyTypes);
    
                ILGenerator methodGetIL = methodGetBuilder.GetILGenerator();
    
                methodGetIL.Emit(OpCodes.Ldarg_0);
                methodGetIL.Emit(OpCodes.Ldfld, fieldBuider);
                methodGetIL.Emit(OpCodes.Ret);
    
                MethodBuilder methodSetBuilder =
                    typeBuilder.DefineMethod($"set_{name}",
                                               getSetAttr,
                                               null,
                                               new Type[] { propType });
    
                ILGenerator methodSetIL = methodSetBuilder.GetILGenerator();
    
                methodSetIL.Emit(OpCodes.Ldarg_0);
                methodSetIL.Emit(OpCodes.Ldarg_1);
                methodSetIL.Emit(OpCodes.Stfld, fieldBuider);
                methodSetIL.Emit(OpCodes.Ret);
    
                propertyBuilder.SetGetMethod(methodGetBuilder);
                propertyBuilder.SetSetMethod(methodSetBuilder);
    
            }
    
            public class ClassDescriptorKeyValue
            {
                public ClassDescriptorKeyValue(string name, Type type, Func<PersonalData, object> valueGetter)
                {
                    Name = name;
                    ValueGetter = valueGetter;
                    Type = type;
                }
    
                public string Name;
                public Type Type;
                public Func<PersonalData, object> ValueGetter;
            }
    
            ///
            ///Your Custom class description based on any source class for example
            /// PersonalData
            public static IEnumerable<ClassDescriptorKeyValue> GetAnonymousClassDescription(bool includeAddress, bool includeFacebook)
            {
                yield return new ClassDescriptorKeyValue("Id", typeof(string), x => x.Id);
                yield return new ClassDescriptorKeyValue("Name", typeof(string), x => x.FirstName);
                yield return new ClassDescriptorKeyValue("Surname", typeof(string), x => x.LastName);
                yield return new ClassDescriptorKeyValue("Country", typeof(string), x => x.Country);
                yield return new ClassDescriptorKeyValue("Age", typeof(int?), x => x.Age);
                yield return new ClassDescriptorKeyValue("IsChild", typeof(bool), x => x.Age < 21);
    
                if (includeAddress)
                    yield return new ClassDescriptorKeyValue("Address", typeof(string), x => x?.Contacts["Address"]);
                if (includeFacebook)
                    yield return new ClassDescriptorKeyValue("Facebook", typeof(string), x => x?.Contacts["Facebook"]);
            }
    
            ///
            ///Source Data Class for example
            /// of cause you can use any other class
            public class PersonalData
            { 
                public int Id { get; set; }
                public string FirstName { get; set; }
                public string LastName { get; set; }
                public string Country { get; set; }
                public int Age { get; set; }
    
                public Dictionary<string, string> Contacts { get; set; }
            }
    
        }
    }
    
    

    DynamicTypeBuilder的使用也很简单,只需要这样写几行:

        public class ExampleOfUse
        {
            private readonly bool includeAddress;
            private readonly bool includeFacebook;
            private readonly dynamic dynamicType;
            private readonly List<ClassDescriptorKeyValue> classDiscriptionList;
            public ExampleOfUse(bool includeAddress = false, bool includeFacebook = false)
            {
                this.includeAddress = includeAddress;
                this.includeFacebook = includeFacebook;
                this.classDiscriptionList = DynamicTypeBuilderTest.GetAnonymousClassDescription(includeAddress, includeFacebook).ToList();
                this.dynamicType = DynamicTypeBuilderTest.CreateAnonymousDynamicType("VeryPrivateData", this.classDiscriptionList);
            }
    
            public object Map(PersonalData privateInfo)
            {
                object dynamicObject = DynamicTypeBuilderTest.CreateAnonymousDynamicInstance(privateInfo, this.dynamicType, classDiscriptionList);
    
                return dynamicObject;
            }
    
        }
    

    我希望这段代码 sn-p 对某人有所帮助 =) 享受!

    【讨论】:

      猜你喜欢
      • 2023-04-08
      • 2011-04-30
      • 1970-01-01
      • 2017-07-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-04-05
      相关资源
      最近更新 更多