. NET Отражение в 3 раза медленнее. NET 4.7.x, чем в 3.5 - PullRequest
5 голосов
/ 22 января 2020

У меня есть приложение, которое мы обновили форму. NET 3.5 до. NET 4.7.2. Единственная проблема на самом деле - это производительность части нашего кода, которая использует отражение. Всю ситуацию лучше всего объяснить на простом примере, который я загрузил в Gist: https://gist.github.com/vkocjancic/3e8a6b3496c412a75b1c85a1d2ba1111

По сути, у нас есть класс POCO, методы свойств которого генерируют исключения, если для свойств не установлено значение ненулевых типов.

[РЕДАКТИРОВАТЬ]:

  1. Да, я знаю, что это не правильно или хороший шаблон для использовать, но приложение запустилось в. NET 1.1.

  2. Да, оно должно быть исправлено долго a go. Это не было.

Затем используется отражение, чтобы получить имена свойств и значения экземпляров класса 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

Может кто-нибудь объяснить, почему отражение примерно в 3 раза медленнее. NET 4.7.2, чем в. NET 3.5 и как это исправить. Задержка происходит только тогда, когда свойства не установлены и выдают исключения. Если вы заполняете значения свойств, разница в производительности отсутствует.

Если я запускаю sample в отладчике, сборка. NET 3.5 никогда не вызывает исключение MissingFieldException. Сборка с использованием. NET 4.7.2 запускает каждое исключение.

[EDIT]

Как упоминалось @bevan, замедление фактически происходит при переключении на. NET 4.0. > Кроме того, проблема сводится к тому, что исключение выдается и обрабатывается в 3 раза быстрее. NET 3.5, чем в. NET 4.0

1 Ответ

5 голосов
/ 22 января 2020

Как я уже упоминал в комментариях, если вы вызовете функцию 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 мс, которые у вас были раньше.

Если бы вы могли изменить это, я бы использовал кэшированные делегаты, такие как Mar c Gravell предлагаемый .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...