给定此方法签名:
void Foo<T>(Func<T, object> expression)
是否可以使用反射来创建
Func<dynamic, object>
用于
MakeGenericType
对于
expression
参数的类型?“显而易见”的方法不是有效的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#语言中的一个特例--幕后黑箱“魔术”行为以某种方式附加到
object
.我想,问题是什么原因
对象
特别是当我写这样的东西时:
Foo<dynamic>(n => new { n.prop });
自从
动态
倾向于生成一系列“你的体系结构糟糕透顶”的回复,我将通过解释真实场景来抢先回答这些问题:我正在使用Roslyn脚本API从配置加载和编译表达式委托,以过滤、解构或以其他方式更改各种对象(包括匿名类型,因此
动态
)写入结构化记录器(Serilog)。
我开始认为这是反射无法处理的边缘情况。(我一直希望避免表达,但我想知道这是否能以某种方式实现。)
编辑:实数代码
示例输入(实际有效)可能是
Sample.Account
(我的测试控制台程序中的一个类)和
a => new { a.Username }
作为要编译的转换表达式,演示了一个存储用户名和密码的帐户类的常见结构化日志记录示例,您可以使用解构来删除密码。(我已经填充了
ScriptingOptions
在调用之前使用必要的程序集引用和导入。)
来自此的输出(使用上述输入)将是
Func<Sample.Account, object>
.问题是如何做到这一点
函数(&L);动态,对象(&T);
作为输出(可以作为源代码编写和编译,但据我所知,不能通过反射进行设置)。
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;
}