[英]Represent the type Func<dynamic, object> via reflection
鉴于此方法签名:
void Foo<T>(Func<T, object> expression)
是否可以使用反射来创建Func<dynamic, object>
的类型表示形式,以与expression
参数的类型一起使用MakeGenericType
? 将“明显”的方法是无效的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#语言中的一个特例 - 幕后黑框“魔法”行为以某种方式附着在一个object
。 我想,这个问题是当我写这样的东西时,这个object
特殊之处:
Foo<dynamic>(n => new { n.prop });
由于dynamic
往往会产生一系列“你的架构糟透了”的回复,我将通过解释现实世界的场景来抢占它们:我正在使用Roslyn Scripting API来加载和编译表达式委托,从配置到过滤,析构或者否则改变写入结构化记录器(Serilog)的各种对象(包括匿名类型,因此是dynamic
)。
我开始认为这是一个反射无法处理的边缘情况。 (我一直希望避免使用表达式,但我想知道是否可以以某种方式将它拉下来。)
示例输入(实际工作)可能是Sample.Account
(我的测试控制台程序中的一个类)和a => new { a.Username }
作为要编译的转换表达式,演示了一个帐户类存储的常见结构化日志记录示例用户名和密码,并使用解构来删除密码。 (在调用之前,我已经使用必要的程序集引用和导入填充了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) });
不幸的是,虽然我尝试过,但我不太了解你的用例,所以无法就使用什么来提供合理的建议。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.