我正在尝试为已经存在的对象调用反序列化构造函数。我该如何使用表达式树呢?

我试过了:

// 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/

10-17 02:40