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