请看下面的例子:
void Main()
{
// APPROACH 1: With an anonymous type
var myObject = new {
Property1 = "PropertyValue1"
};
// WORKS: Properties contains "Property1"
var properties = myObject.GetType().GetProperties();
// APPROACH 2: With an expando object
dynamic myObject2 = new ExpandoObject();
myObject2.Property1 = "PropertyValue1";
// DOES NOT WORK: Properties2 is null or empty
var properties2 = myObject2.GetType().GetProperties();
}
我要的是让 Type.GetProperties()
工作在一个动态生成的类型。我真正明白为什么它工作在方式1,而不是2。事实上,在办法1,编译器有oportunity产生一个匿名类型,看起来完全是一个命名的类型等。在方法2,但是,编译时类型实际上是一个ExpandoObject,所以反射不能正常工作。
What I want is to make Type.GetProperties()
to work on a dynamically generated type. I really understand why it works in the approach 1 and not 2. Actually, in the approach 1, the compiler has the oportunity to generate an anonymous type that looks exactly like a named type. In the approach 2, however, the compile time type is actually an ExpandoObject, so reflection doesn't work properly.
如何创建一个运行时的对象,这是动态的,也通常与反思的工作,如的GetProperties,
的方法?
How do I create a runtime object, that is dynamic and will also work normally with reflection, like the GetProperties
method?
修改
感谢所有的答案,但我真正明白,我知道如何从ExpandoObject键和值。该问题是,我需要一个动态创建的实例传递给方法,我的控制将外,在反过来,调用实例的GetProperties,()。
Thanks for all answers, but I really understand and I know how to get the keys and values from the ExpandoObject.. The problem is that I need to pass a dynamically created instance to a method, outside my control that will, in turn, call GetProperties() on the instance.
为了通过反射一个动态构造类型得到的值,你需要使用 Reflection.Emit的
。这是不理想的,因为它需要你正确地发出MSIL。如果您使用的情况下,只需要简单的属性访问,那么它可能是可行的,但不明智的。
In order to get the values via reflection for a dynamically-constructed type, you'll need to use Reflection.Emit
. This is less than ideal as it requires you to properly emit MSIL. If your use case requires only simple property access, then it may be feasible, though ill-advised.
下面是一个简单的,轻测试,类型,使用 Reflection.Emit的
生成器:
Here's a simple, lightly-tested, type builder that uses Reflection.Emit
:
public static class TypeBuilderUtil {
public static Type BuildDynamicType() {
var typeBuilder = CreateTypeBuilder( "DynamicType" );
CreateProperty( typeBuilder, "Property1", typeof ( string ) );
var objectType = typeBuilder.CreateType();
return objectType;
}
private static TypeBuilder CreateTypeBuilder( string typeName ) {
var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly( new AssemblyName( "DynamicAssembly" ), AssemblyBuilderAccess.Run );
var moduleBuilder = assemblyBuilder.DefineDynamicModule( "DynamicModule" );
var typeBuilder = moduleBuilder.DefineType( typeName,
TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.AutoClass | TypeAttributes.AnsiClass | TypeAttributes.BeforeFieldInit | TypeAttributes.AutoLayout
, null );
return typeBuilder;
}
private static void CreateProperty( TypeBuilder typeBuilder, string propertyName, Type propertyType ) {
var backingFieldBuilder = typeBuilder.DefineField( "_" + propertyName, propertyType, FieldAttributes.Private );
var propertyBuilder = typeBuilder.DefineProperty( propertyName, PropertyAttributes.HasDefault, propertyType, null );
// Build setter
var getterMethodBuilder = typeBuilder.DefineMethod( "get_" + propertyName, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, propertyType, Type.EmptyTypes );
var getterIl = getterMethodBuilder.GetILGenerator();
getterIl.Emit( OpCodes.Ldarg_0 );
getterIl.Emit( OpCodes.Ldfld, backingFieldBuilder );
getterIl.Emit( OpCodes.Ret );
// Build setter
var setterMethodBuilder = typeBuilder.DefineMethod( "set_" + propertyName, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, null, new[] {propertyType} );
var setterIl = setterMethodBuilder.GetILGenerator();
setterIl.Emit( OpCodes.Ldarg_0 );
setterIl.Emit( OpCodes.Ldarg_1 );
setterIl.Emit( OpCodes.Stfld, backingFieldBuilder );
setterIl.Emit( OpCodes.Ret );
propertyBuilder.SetGetMethod( getterMethodBuilder );
propertyBuilder.SetSetMethod( setterMethodBuilder );
}
}
您将创建类型,然后填充它是这样:
You would create the type, then populate it as such:
var myType = TypeBuilderUtil.BuildDynamicType();
var myObject = Activator.CreateInstance( myType );
// Set the value
var propertyInfo = myObject.GetType().GetProperty( "Property1", BindingFlags.Instance | BindingFlags.Public );
propertyInfo.SetValue( myObject, "PropertyValue", null );