sir*_*lot 5 c# serialization expression-trees
我正在尝试为已经存在的对象调用反序列化构造函数.我如何使用表达式树来做到这一点?
我试过了:
// 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 });
Run Code Online (Sandbox Code Playgroud)
但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() });
Run Code Online (Sandbox Code Playgroud)
我害怕它的表现,但它似乎是唯一的方法.
更新
现在有一个正确的答案.谢谢大家.
如果要使用表达式树,请使用Expression.New.这是一个例子
var info = Expression.Parameter(typeof(SerializationInfo), "info");
var context = Expression.Parameter(typeof(StreamingContext), "context");
var callTheCtor = Expression.New(ctorInfo, info, context);
Run Code Online (Sandbox Code Playgroud)
这不适用于现有对象,但由于您的代码显示GetUninitializedObject我认为您可以删除该部分并用于Expression.New创建新对象.
小智 6
如果我正确地阅读你的问题,你并不关心是否通过表达式树调用构造函数,只要实际的调用不需要反射.您可以构建一个转发到构造函数调用的动态方法:
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++;
}
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,这表现得像常规方法调用.x在打印其值之前未设置,因此0在再次调用构造函数时不会重置它.根据构造函数的作用,这可能是也可能不是问题.
| 归档时间: |
|
| 查看次数: |
3852 次 |
| 最近记录: |