Подтвердить что ты не робот

Как медленно отражается

Недавно я создал интерфейсный слой, чтобы отличить DataAccessProvider от нашего уровня бизнес-логики. При таком подходе мы можем изменить наш выбор DataAccessProvider всякий раз, когда хотим, изменив значения в Web/App.Config. (при необходимости можно указать более подробную информацию).

В любом случае, для этого мы используем рефлексию для выполнения нашего класса DataProvider, над которым мы можем работать.

/// <summary>
/// The constructor will create a new provider with the use of reflection.
/// If the assembly could not be loaded an AssemblyNotFoundException will be thrown.
/// </summary>
public DataAccessProviderFactory()
{
    string providerName = ConfigurationManager.AppSettings["DataProvider"];
    string providerFactoryName = ConfigurationManager.AppSettings["DataProviderFactory"];
    try
    {
        activeProvider = Assembly.Load(providerName);
        activeDataProviderFactory = (IDataProviderFactory)activeProvider.CreateInstance(providerFactoryName);
    }
    catch
    {
        throw new AssemblyNotFoundException();
    }
}

Но теперь мне интересно, как медленное отражение?

4b9b3361

Ответ 1

В большинстве случаев: более чем достаточно быстро. Например, если вы используете это для создания объекта-оболочки DAL, время, затрачиваемое на создание объекта посредством отражения, будет minuscule по сравнению с временем, которое требуется для подключения к сети. Поэтому оптимизация этого будет пустой тратой времени.

Если вы используете отражение в узком цикле, есть уловки, чтобы улучшить его:

  • generics (используя обертку where T : new() и MakeGenericType)
  • Delegate.CreateDelegate (для типизированного делегата, не работает для конструкторов)
  • Reflection.Emit - хардкор
  • Expression (например, Delegate.CreateDelegate, но более гибкий и работает для конструкторов)

Но для ваших целей CreateInstance отлично. Придерживайтесь этого и делайте все просто.


Изменить: в то время как точка относительно относительной производительности остается, и, хотя самое главное, "измерить ее", остается, я должен прояснить некоторые из вышеперечисленных. Иногда... это имеет значение. Сначала измерьте. Однако, если вы обнаружите, что это слишком медленно, вы можете посмотреть на что-то вроде FastMember, который делает все Reflection.Emit код тихо в фоновом режиме, чтобы дать вам простой API; например:

var accessor = TypeAccessor.Create(type);
List<object> results = new List<object>();
foreach(var row in rows) {
    object obj = accessor.CreateNew();
    foreach(var col in cols) {
        accessor[obj, col.Name] = col.Value;
    }
    results.Add(obj);
}

который прост, но будет очень быстрым. В конкретном примере я упоминаю об DAL-обертке - если вы делаете этот лот, рассмотрите что-то вроде dapper, что снова делает все Reflection.Emit в фоновом режиме, чтобы предоставить вам самый быстрый, но простой в использовании API:

int id = 12345;
var orders = connection.Query<Order>(
    "select top 10 * from Orders where CustomerId = @id order by Id desc",
    new { id }).ToList();

Ответ 2

Его медленнее по сравнению с неотражающим кодом. Важно не то, если он медленный, но если его медленный , где он считает. Например, если вы создаете объекты, используя отражение в веб-среде, где ожидаемая согласованность может вырасти до 10K, это будет медленным.

В любом случае, это хорошо, чтобы не беспокоиться о производительности заранее. Если все оказывается слишком медленным, вы всегда можете ускорить их, если вы правильно разработали, чтобы части, которые вы ожидали, нуждались в оптимизации в будущем, локализованы.

Вы можете проверить эту знаменитую статью, если вам нужно ускорить:

Динамический... Но быстрый: рассказ о трех обезьянах, волках и классах DynamicMethod и ILGenerator

Ответ 4

Отражение не так медленно. Вызов метода отражением примерно в 3 раза медленнее обычного. Это не проблема, если вы делаете это только один раз или в некритических ситуациях. Если вы используете его 10'000 раз в критическом по времени методе, я бы подумал об изменении реализации.

Ответ 5

Помимо ссылок, приведенных в других ответах, и обеспечения того, что вы не пишете "патологически плохой" код, для меня лучшим ответом на это является проверка его самостоятельно.

Только вы знаете, где у вас бутылочные шеи, сколько раз ваш код отражения будет пользователем, будет ли код отражения в жестких петлях и т.д. Вы знаете свое деловое дело, сколько пользователей будет получать доступ к вашему сайту, требования.

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

Возможности веб-тестирования и тестирования производительности VS.NET должны сделать измерение производительности этого кода довольно простым.

Если вы не используете отражение, как будет выглядеть ваш код? Какие ограничения у него будут? Возможно, вы не можете жить с ограничениями, с которыми вы сталкиваетесь, если вы удалите код отражения. Возможно, стоит попробовать создать этот код без отражения, чтобы увидеть, возможно ли это, или же это альтернатива желательна.

Ответ 6

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

С отражением

  • Выполнение 58 объектов путем итерации по каждому из их Атрибутов и сопоставления
  • Общее время: 52254 наносекунды

    while (reader.Read()) {
        string[] columns = reader.CurrentRecord;
        CdsRawPayfileEntry toAdd = new CdsRawPayfileEntry();
        IEnumerable<PropertyInfo> rawPayFileAttributes = typeof(CdsRawPayfileEntry).GetProperties().Where(prop => Attribute.IsDefined(prop, typeof(CustomIndexAttribute)));
        foreach (var property in rawPayFileAttributes) {
            int propertyIndex = ((CustomIndexAttribute)property.GetCustomAttribute(typeof(CustomIndexAttribute))).Index;
            if (propertyIndex < columns.Length)
                property.SetValue(toReturn, columns[propertyIndex]);
            else
                break;
        }
    }
    

Без отражения

  • Создание объектов 58 путем создания нового объекта
  • Общее время: 868 наносекунд

        while (reader2.Read()) {
            string[] columns = reader2.CurrentRecord;
            CdsRawPayfileEntry toAdd = new CdsRawPayfileEntry() {
                ColumnZero = columns[0],
                ColumnOne = columns[1],
                ColumnTwo = columns[2],
                ColumnThree = columns[3],
                ColumnFour = columns[4],
                ColumnFive = columns[5],
                ColumnSix = columns[6],
                ColumnSeven = columns[7],
                ColumnEight = columns[8],
                ColumnNine = columns[9],
                ColumnTen = columns[10],
                ColumnEleven = columns[11],
                ColumnTwelve = columns[12],
                ColumnThirteen = columns[13],
                ColumnFourteen = columns[14],
                ColumnFifteen = columns[15],
                ColumnSixteen = columns[16],
                ColumnSeventeen = columns[17]
            };
        }
    

Хотя это не совсем справедливо, так как отражению также необходимо получить конкретный атрибут каждого свойства 58 * 18 раз поверх создания нового объекта посредством отражения, но он по крайней мере обеспечивает некоторую перспективу.

Ответ 7

Я делал нечто похожее до тех пор, пока не начал играть с IoC. Я бы использовал определение объекта Spring для указания поставщика данных - SQL, XML или Mocks!