通过反射表示类型 Func<dynamic, object>

Represent the type Func<dynamic, object> via reflection

给定此方法签名:

void Foo<T>(Func<T, object> expression)

是否可以使用反射来创建 Func<dynamic, object> 的类型表示以与 MakeGenericType 一起用于 expression 参数的类型? "obvious" 方法不是有效的 C# 语法,因为 dynamic 既不是类型也不是对象(即 typeof(dynamic) 无效),所以我无法想出任何有用的东西对于下面的 ??? 参数:

Type fnType = typeof(Func<,>).MakeGenericType(new Type[] { ???, typeof(object) });

有趣的是,我 可以 这样做并且编译没有错误,但脚本编译器在运行时抛出,我认为因为 typeof 确实返回了 Func<object, object>:

Type fn = typeof(Func<dynamic, object>);

至少,我可以通过反射或调试器找到的任何东西似乎都与 typeof(Func<object, object>) 没有区别。当然,我知道 dynamic 是 C# 语言中的一个特例——幕后黑盒 "magic" 行为以某种方式附加到 object。我想,问题是当我写这样的东西时,是什么让 object 如此特别:

Foo<dynamic>(n => new { n.prop });

由于 dynamic 往往会产生一连串的 "your architecture sucks" 回复,我将通过解释真实世界的场景来抢占这些回复:我正在使用 Roslyn 脚本 API 来从配置加载和编译表达式委托以过滤、解构或以其他方式更改写入结构化记录器 (Serilog) 的各种对象(包括匿名类型,因此 dynamic)。

我开始认为这是反射无法处理的边缘情况。 (我一直希望避免使用表达式,但我想知道这是否可以以某种方式实现。)

编辑:真实代码

示例输入(实际有效)可能是 Sample.Account(我的测试控制台程序中的 class)和 a => new { a.Username } 作为要编译的转换表达式,展示了一个常见的结构化-存储用户名和密码的帐户 class 的日志记录示例,您使用解构来剥离密码。 (在调用之前,我已经使用必要的程序集引用和导入填充 ScriptingOptions。)

此输出(使用上述输入)将是 Func<Sample.Account, object> 的一个实例。问题是如何做这种事情以获得 Func<dynamic, object> 作为输出(可以编写和编译为源代码,但据我所知,不能通过反射设置)。

private static dynamic CompileTransformation(string transformedType, string transformation)
{
    // get a Type that corresponds to namespace.type in transformedType
    Type TValue = Type.GetType(transformedType) ??
        AppDomain.CurrentDomain.GetAssemblies()
        .Select(a => a.GetType(transformedType))
        .FirstOrDefault(t => t != null);

    // get a representation of Func<TValue, object>
    Type funcType = typeof(Func<,>).MakeGenericType(new Type[] { TValue, typeof(object) });

    // get a representation of CSharpScript.EvaluateAsync<Func<TValue, object>>()
    var evalMethod = typeof(CSharpScript).GetMethods()
        .FirstOrDefault(m => m.Name.Equals("EvaluateAsync") && m.IsGenericMethod)
        .MakeGenericMethod(funcType);

    // execute EvaluateAsync
    dynamic evalTask = evalMethod.Invoke(null, new object[] { transformation, ReflectionHelper.scriptOptions, null, null, null });
    dynamic compiledFunc = evalTask.GetAwaiter().GetResult();

    return compiledFunc;
}

不可能通过反射来做到这一点,因为 dynamic 概念只存在于编译时,而不是 运行 时。

如果你编译如下:

dynamic x = "test";
Console.WriteLine(x.Length);

反编译结果类似于 DotPeek - 您会看到编译器已将您的 dynamic 代码转换成的一大堆神秘的、类似反射的代码。而x确实是object类型的,所以整个事情和typeof(string).GetProperty("Length").GetValue(x)基本类似,但可能更有效。但是在任何地方你都看不到 dynamic 本身的任何踪迹。

因此,无法在 运行 时以某种方式从 Func<T, object> 获得 Func<dynamic, object>

Foo<dynamic>(n => new { n.prop });

在概念上类似于:

Foo<object>((object n) => new { prop = n.GetType().GetProperty("prop").GetValue(n) });

不幸的是,尽管我尝试过,但我不太了解您的用例,因此无法就使用什么提供合理的建议。