Аудит объектов с использованием отражения - PullRequest
4 голосов
/ 02 февраля 2012

это снова я! :)

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

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

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

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

Кроме того - они сохраняют ключевую ценность в моих руках.

Любая помощь была бы блестящей ..

Приветствия:)

// Поднимается код стены ..

    public static void AuditObject(ITraceable obj)
    {
        if (obj == null)
            return;

        IEnumerable<PropertyInfo> properties = GetPropertyInfo(obj);

        List<SerializeableKeyValuePair<string, object>> kvpList =
            new List<SerializeableKeyValuePair<string, object>>();

        foreach (PropertyInfo property in properties)
        {
            SerializeableKeyValuePair<string, object> thisValue = new SerializeableKeyValuePair<string, object>();

            thisValue.Key = property.Name;

            thisValue.Value = GetPropertyValue(obj, property);

            if (thisValue.Value != null)
                kvpList.Add(thisValue);
        }

        TestObject o = CreateObjectFromHistory<TestObject>(kvpList);
    }

    public static T CreateObjectFromHistory<T>(List<SerializeableKeyValuePair<string, object>> history)
        where T : class, ITraceable
    {
        T historicalObject = Activator.CreateInstance<T>();

        Dictionary<string, PropertyInfo> propertys = GetPropertysAsDictionary(historicalObject);

        foreach (SerializeableKeyValuePair<string, object> kvp in history)
        {
            if (!propertys.ContainsKey(kvp.Key))
                continue;

            PropertyInfo prop = propertys[kvp.Key];

            if (prop == null)
                continue;

            var value = CoerceValue(prop.PropertyType, kvp.Value);

            prop.SetValue(historicalObject, value, null);

        }

        return historicalObject;

    }

    private static object CoerceValue(Type type, object value)
    {
        if (type == typeof(string))
            return value as string;

        return null;
    }

    private static object GetPropertyValue(ITraceable obj, PropertyInfo property)
    {
        if (property.PropertyType == typeof(string))
            return GetProperyValueByType<string>(property.GetValue(obj, null));
        else if (property.PropertyType == typeof(DateTime))
            return GetProperyValueByType<DateTime>(property.GetValue(obj, null));

        return null;
    }

    private static IEnumerable<PropertyInfo> GetPropertyInfo(ITraceable obj)
    {
        List<PropertyInfo> properties;

        Type objType = obj.GetType();

        if (PropertyDictionary.TryGetValue(objType, out properties) == false)
        {
            properties = obj.GetType().GetProperties(BindingFlags.Public |
                                                     BindingFlags.Instance).ToList();

            properties.RemoveAll(p => IgnoreProperty(p.GetCustomAttributes(typeof(DoNoTraceAttribute), false)));

            PropertyDictionary.Add(objType, properties);
        }

        return properties;
    }

    private static Dictionary<string, PropertyInfo> GetPropertysAsDictionary(ITraceable obj)
    {
        return GetPropertyInfo(obj).ToDictionary(pro => pro.Name);
    }

    private static object GetProperyValueByType<T>(object value)
    {
        T actualType = (T)value;

        if (actualType.Equals(default(T)))
            return default(T);

        //this will need further implementation

        return (T)value;
    }

    private static bool IgnoreProperty(IEnumerable<object> p)
    {
        return p.AsParallel().OfType<DoNoTraceAttribute>().Any();
    }

Обновлен код;

   private static IEnumerable<PropertyInfo> GetPropertyInfo(ITraceable obj)
    {
        List<PropertyInfo> properties;

        Type objType = obj.GetType();

        if (PropertyDictionary.TryGetValue(objType, out properties) == false)
        {
            properties = obj.GetType().GetProperties(BindingFlags.Public |
                                                     BindingFlags.Instance).ToList();

            properties.RemoveAll(p => Attribute.IsDefined(p, typeof(DoNoTraceAttribute)));

            PropertyDictionary.Add(objType, properties);
        }

        return properties;
    }

Это выглядит лучше?

1 Ответ

3 голосов
/ 02 февраля 2012

Если вы используете PropertyInfo.GetValue() во время выполнения, производительность всегда будет низкой. Чтобы получить хорошую производительность (особенно для просмотра большого количества объектов), вам нужно посмотреть что-то вроде ILGenerator или Expression - или вы можете просто использовать что-то вроде FastMember и получить доступ к значениям через prop.Name. Я действительно не думаю, что IgnoreProperty реализован хорошо - вы должны просто посмотреть на Attribute.IsDefined здесь; нет необходимости в LINQ, нет необходимости в Parallel и не нужно материализовать атрибуты.

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