c#-通过反射表示类型Func
作者:互联网
给定此方法签名:
void Foo<T>(Func<T, object> expression)
是否有可能使用反射来创建Func< dynamic,object>的类型表示.与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>)不可区分.当然,我意识到动态是C#语言中的一种特例-幕后黑匣子“魔术”行为以某种方式附加到对象上.我想的问题是,当我写这样的东西时,是什么使那个对象变得特别:
Foo<dynamic>(n => new { n.prop });
由于动态趋向于产生一连串的“您的体系结构糟透了”的答复,因此,我将通过解释实际情况来抢占这些答复:我使用Roslyn脚本API来加载和编译表达式委托,从配置到过滤,解构或否则更改写入结构化记录器(Serilog)的各种对象(包括匿名类型,因此是动态的).
我开始认为这是反射无法解决的极端情况. (我一直希望避免使用Expressions,但是我想知道这是否可以解决问题.)
编辑:实码
示例输入(实际上有效)可能是Sample.Account(测试控制台程序中的类)和==>. 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 x = "test";
Console.WriteLine(x.Length);
反编译会产生类似DotPeek的结果-您会看到很多隐秘的,类似反射的代码,编译器已将它们转换为动态代码.而且x实际上是对象类型,因此整个过程基本上类似于typeof(string).GetProperty(“ Length”).GetValue(x),但可能更有效.但是在任何地方都看不到任何动态本身的痕迹.
因此,没有办法以某种方式获得Func< dynamic,object>.来自Func< T,object>在运行时.
Foo<dynamic>(n => new { n.prop });
在概念上类似于以下内容:
Foo<object>((object n) => new { prop = n.GetType().GetProperty("prop").GetValue(n) });
不幸的是,尽管我尝试过,但我还是不太了解您的用例,因此无法就使用什么给出合理的建议.
标签:net-standard-2-0,reflection,generics,c 来源: https://codeday.me/bug/20191109/2011225.html