And*_*ena 6 .net c# reflection
请看以下示例:
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();
}
Run Code Online (Sandbox Code Playgroud)
我想要的是Type.GetProperties()使用动态生成的类型.我真的理解为什么它在方法1而不是2中工作.实际上,在方法1中,编译器有机会生成一个看起来与命名类型完全相同的匿名类型.但是,在方法2中,编译时类型实际上是一个ExpandoObject,因此反射不能正常工作.
如何创建一个动态的运行时对象,并且还可以通过反射正常工作,就像GetProperties方法一样?
编辑
感谢所有答案,但我真的理解并且我知道如何从ExpandoObject获取密钥和值.问题是我需要将一个动态创建的实例传递给一个方法,在我的控制之外,它将依次调用实例上的GetProperties().
你不需要反思ExpandoObject.这真的只是一个奇特的实现IDictionary<string, object>.你可以这样投,然后你会有一个字典,其中键是属性名称,值是属性值:
// Create your object
dynamic myObject2 = new ExpandoObject();
// Cast to IDictionary<string, object>
var myObjectDictionary = (IDictionary<string, object>)myObject2;
// Get List<string> of properties
var propertyNames = myObjectDictionary.Keys.ToList();
Run Code Online (Sandbox Code Playgroud)
另一种选择是使用的特点IDynamicMetaObjectProvider,这ExpandoObject也实现了.用法如下:
var metaObjectProvider = (IDynamicMetaObjectProvider)myObject2;
var propertyNames = metaObjectProvider
.GetMetaObject(Expression.Constant(metaObjectProvider))
.GetDynamicMem??berNames();
Run Code Online (Sandbox Code Playgroud)
在这种情况下,propertyNames将IEnumerable<string>使用动态成员名称.
为了通过动态构造类型的反射获取值,您需要使用Reflection.Emit. 这不太理想,因为它要求您正确发出 MSIL。如果您的用例仅需要简单的属性访问,那么它可能是可行的,尽管不明智。
这是一个简单的、经过轻微测试的类型生成器,它使用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 );
}
}
Run Code Online (Sandbox Code Playgroud)
您将创建类型,然后按如下方式填充它:
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 );
Run Code Online (Sandbox Code Playgroud)