繁体   English   中英

代表类型Func <dynamic, object> 通过反思

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM