Эффективно ли запоминать метаданные типа при использовании .NET Reflection API? - PullRequest
2 голосов
/ 21 июня 2011

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

  • Вызов typeof(T).GetProperties() много раз для одного и того же типа T.
  • Запоминание найденных свойств в Dictionary<Type, PropertyInfo[]>.

Вот код, который я написал, используя первый подход:

private static T MakeElement<T>(SqlDataReader reader) where T : class, new() {
    T element = new T();
    PropertyInfo[] properties = typeof(T).GetProperties(); // critical line

    foreach (PropertyInfo property in properties)
        property.SetValue(element, reader[property.Name], null);

    return element;
}

public static T RetrieveElement<T>() where T : class, new() {
    T element = null;

    actions.Add(delegate(SqlDataReader reader) {
        if (reader.Read())
            element = MakeElement<T>(reader);
    });

    Execute();
    return element;
}

public static List<T> RetrieveList<T>() where T : class, new() {
    List<T> list = new List<T>();

    actions.Add(delegate(SqlDataReader reader) {
        while (reader.Read())
            list.Add(MakeElement<T>(reader));
    });

    Execute();
    return list;
}

// For the sake of completeness, here is the Execute method.
public static void Execute() {
    SqlConnectionStringBuilder connStringBuilder = new SqlConnectionStringBuilder();
    connStringBuilder.DataSource     = DataSource;
    connStringBuilder.InitialCatalog = InitialCatalog;
    connStringBuilder.UserID         = UserID;
    connStringBuilder.Password       = Password;

    using (SqlConnection connection = new SqlConnection(connStringBuilder.ConnectionString))
    using (SqlCommand command = new SqlCommand(StoredProcedure, connection)) {
        command.CommandType = CommandType.StoredProcedure;

        SqlParameterCollection parameterCollection = command.Parameters;
        foreach (KeyValuePair<string, object> parameter in parameters)
            parameterCollection.AddWithValue(parameter.Key, parameter.Value);

        try {
            connection.Open();
            using (SqlDataReader reader = command.ExecuteReader())
                foreach (Action<SqlDataReader> action in actions) {
                    action(reader);
                    reader.NextResult();
                }
        }
        finally {
            parameters.Clear();
            actions.Clear();
        }
    }
}

Я уже думал о том, какой подход может быть более эффективным:

Для прямого вызова GetProperties:

  • Метаданные все равно есть. Его не нужно реконструировать, просто восстановить.

Для запоминания:

  • Метаданные могут быть в формате, не понятном непосредственно приложению C #, поэтому в GetProperties может быть проведена некоторая предварительная обработка.
  • Метаданные есть, а массив PropertyInfo нет, и, следовательно, его необходимо восстановить.

Дополнительный вопрос: Есть ли какая-то причина, по которой API отражения .NET использует массивы вместо индексаторов для получения метаданных типа?

Ответы [ 2 ]

1 голос
/ 21 июня 2011

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

0 голосов
/ 13 января 2015

Еще лучше:

public static class Memoizer<T>
{
    public static readonly PropertyInfo[] Properties = typeof(T).GetProperties();
}

Просто убедитесь, что массив не изменился, или вместо этого оберните его в ReadOnlyCollection .

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