簡體   English   中英

.NET 反射在 .NET 4.7.x 中比在 3.5 中慢 3 倍

[英].NET reflection 3 times slower in .NET 4.7.x than in 3.5

我有一個從 .NET 3.5 升級到 .NET 4.7.2 的應用程序。 唯一的問題確實是我們使用反射的部分代碼的性能。 整個情況在我上傳到 Gist 的一個簡單示例中得到了最好的解釋: https ://gist.github.com/vkocjancic/3e8a6b3496c412a75b1c85a1d2ba1111

基本上,我們有一個 POCO 類,如果未為不可空類型的屬性設置值,則屬性方法會拋出異常。

[編輯]:

  1. 是的,我知道那是不正確的或不適合使用的模式,但是,該應用程序是從 .NET 1.1 開始的。

  2. 是的,它早就應該修好了。 事實並非如此。

然后使用反射獲取 POCO 類實例的屬性名稱和值,並將其填充到 DataTable。

示例和現實生活中的項目源代碼完全相同。 唯一的區別是,在一種情況下,它是使用 .NET 3.5 編譯的,而在第二種情況下,它是使用 .NET 4.7.2 編譯的。

這是 10 次調用的平均耗時(以毫秒為單位):

.NET 3.5      ->  231.1 ms
.NET 4.7.2    ->  713.5 ms
.NET Core 2.2 -> 1013.2 ms

誰能詳細說明為什么反射在 .NET 4.7.2 中比在 .NET 3.5 中慢 3 倍,以及如何解決這個問題。 只有在未設置屬性並拋出異常時才會發生滯后。 如果您填充屬性值,則性能沒有差異。

如果我在調試器中運行示例,.NET 3.5 構建永遠不會觸發 MissingFieldException。 使用 .NET 4.7.2 構建會觸發每個異常。

[編輯]

正如@bevan 所提到的,減速實際上發生在切換到 .NET 4.0 時。 > 此外,問題歸結為在 .NET 3.5 中拋出和處理異常的速度比在 .NET 4.0 中快 3 倍

正如我在評論中提到的,如果您在訪問屬性之前調用IsPROP_NUMERIC_ANull函數,它不會再拋出任何異常並且速度非常快。

foreach (var myObject in objects)
{
    var row = table.NewRow();

    // TODO implement some caching: dont call GetProperties(), GetMethod(), for every object
    var type = myObject.GetType();
    var properties = type.GetProperties();

    foreach (var info in properties)
    {
        try
        {
            // call the IsNullMethod for the property, eg "IsPROP_NUMERIC_ANull"
            var isNullMethodName = $"Is{info.Name}Null";
            var isNullMethod = type.GetMethod(isNullMethodName, BindingFlags.Instance | BindingFlags.Public);

            if (isNullMethod != null)
            {
                var fldIsNull = (bool)isNullMethod.Invoke(myObject, new object[] { });
                if (!fldIsNull)
                    row[info.Name] = info.GetValue(myObject, null);
            } else
            {
                // isNullMethod doesn't exist
                row[info.Name] = info.GetValue(myObject, null);
            }
        }
        catch
        {
            // do nothing
        }
    }
    table.Rows.Add(row);
}

總運行時間為3 ms ,而之前為 19500 毫秒。

如果您可以重新設計它,我會使用像 Marc Gravell 提議的緩存委托。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM