通过反射表示类型 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) });
不幸的是,尽管我尝试过,但我不太了解您的用例,因此无法就使用什么提供合理的建议。
给定此方法签名:
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) });
不幸的是,尽管我尝试过,但我不太了解您的用例,因此无法就使用什么提供合理的建议。