如何动态创建新的匿名类?
Posted
技术标签:
【中文标题】如何动态创建新的匿名类?【英文标题】: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')。 【参考方案1】:匿名类型只是隐式声明的常规类型。它们与dynamic
关系不大。
现在,如果您要使用 ExpandoObject 并通过 dynamic
变量引用它,您可以即时添加或删除字段。
编辑
当然可以:只需将其转换为 IDictionary<string, object>
。然后就可以使用索引器了。
您使用相同的转换技术来迭代字段:
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();道具为空
您所做的只是说动态属性与强类型属性不同。这是微不足道的事实。
***.com/a/4024786/998793 展示了如何通过转换为通用字典来做到这一点:((IDictionary<string, object>)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 = $"entityNameAssembly";
AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(asmName, AssemblyBuilderAccess.RunAndCollect);
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule($"asmName.NameModule");
TypeBuilder typeBuilder = moduleBuilder.DefineType($"entityNameDynamic", 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 对某人有所帮助 =) 享受!
【讨论】:
以上是关于如何动态创建新的匿名类?的主要内容,如果未能解决你的问题,请参考以下文章