簡體   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