我正在尝试为已经存在的对象调用反序列化构造函数。我该如何使用表达式树呢?
我试过了:
// Create an uninitialized object
T graph = (T)FormatterServices.GetUninitializedObject(graphType);
// (graph, serializationInfo, streamingContext) => graph.Constructor(serializationInfo, streamingContext)
ParameterExpression graphParameter = Expression.Parameter(serializationPack.SelfSerializingBaseClassType, "graph");
ParameterExpression serializationInfoParameter = Expression.Parameter(typeof(SerializationInfo), "serializationInfo");
ParameterExpression streamingContextParameter = Expression.Parameter(typeof(StreamingContext), "streamingContext");
MethodCallExpression callDeserializationConstructor = Expression.Call(graphParameter,
(MethodInfo)serializationPack.SelfSerializingBaseClassType.GetConstructor(new[] { typeof(SerializationInfo), typeof(StreamingContext) }),
new[] { serializationInfoParameter, streamingContextParameter });
但是
Expression.Call
仅接受MethodInfo
而不接受ConstructorInfo
,因此这不起作用-除非有一种方法可以转换为MethodInfo
?更新
我只是使用
ConstructorInfo.Invoke
来增强:// Cache this part
ConstructorInfo deserializationConstructor = serializationPack
.SelfSerializingBaseClassType
.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, CallingConventions.Standard,
new[] { typeof(SerializationInfo), typeof(StreamingContext) }, null);
// Call this when I need it
deserializationConstructor.Invoke(graph, new Object[] { serializationInfo, new StreamingContext() });
我害怕它的性能,但这似乎是实现此目的的唯一方法。
更新
现在有一个正确的答案。谢谢大家
最佳答案
如果我正确地阅读了您的问题,那么您并不在乎是否通过表达式树调用了构造函数,只要实际的调用不需要反射即可。您可以构建转发到构造函数调用的动态方法:
using System;
using System.Reflection;
using System.Reflection.Emit;
namespace ConsoleApplication1
{
static class Program
{
static void Main(string[] args)
{
var constructor = typeof(Foo).GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
var helperMethod = new DynamicMethod(string.Empty, typeof(void), new[] { typeof(Foo) }, typeof(Foo).Module, true);
var ilGenerator = helperMethod.GetILGenerator();
ilGenerator.Emit(OpCodes.Ldarg_0);
ilGenerator.Emit(OpCodes.Call, constructor);
ilGenerator.Emit(OpCodes.Ret);
var constructorInvoker = (Action<Foo>)helperMethod.CreateDelegate(typeof(Action<Foo>));
var foo = Foo.Create();
constructorInvoker(foo);
constructorInvoker(foo);
}
}
class Foo
{
int x;
public static Foo Create()
{
return new Foo();
}
private Foo()
{
Console.WriteLine("Constructor Foo() called, GetHashCode() returns {0}, x is {1}", GetHashCode(), x);
x++;
}
}
}
请注意,这的行为类似于常规方法调用。
x
在打印其值之前未设置,因此当您再次调用构造函数时,不会将其重置为0
。根据构造函数的不同,这可能是问题,也可能不是问题。关于c# - 如何通过现有对象上的表达式树调用构造函数?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/16363838/