编程语言
首页 > 编程语言> > c#-通过反射表示类型Func

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&gt ;:

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