Высокопроизводительный аудит и проверка изменений свойств классов и структур C #

#c# #performance #reflection #.net-3.5 #properties

#c# #Производительность #отражение #.net-3.5 #свойства

Вопрос:

У меня есть несколько структур c #, которые придают форму структурам в очень большом файле данных. Эти структуры интерпретируют биты в словах данных файла и преобразуют их в первоклассные свойства. Вот пример одного:

 [StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct TimeF1_MsgDayFmt
{
    // Time Data Words
    public UInt16 TDW1;
    public UInt16 TDW2;
    public UInt16 TDW3;

    /// <summary>
    /// Tens of milliseconds
    /// </summary>
    public UInt16 Tmn
    {
        // Bits.Get is just a helper method in a static class
        get { return Bits.Get(TDW1, 0, 4); }
        set 
        {
            if (value > 9)
                throw new ArgumentOutOfRangeException();

            TDW1 = Bits.Set(TDW1, value, 0, 4); 
        }
    }

    /// Several other properties follow.
  

Мне нужно сделать две вещи, которые, я думаю, связаны. Во-первых, необходимо иметь возможность проверять весь класс, используя набор правил проверки. Я знаю, что есть несколько способов сделать это; тот, который мне больше всего нравится, — это аннотировать каждое свойство чем-то вроде этого:

 [ValidateRange(0,9)]
public UInt16 Tmn
{
    get { return Bits.Get(TDW1, 0, 4); }
    set 
    {
    /// etc.  Will probably no longer throw the ArgumentOutOfRangeException here.
  

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

 public List<Error> Validate(TimeF1_MsgDayFmt original)
  

Второе, что мне нужно сделать, это выполнить аудит изменений свойств; то есть для каждого свойства, которое изменилось по сравнению с его первоначальным значением, мне нужно иметь возможность получить строку с надписью «Свойство foo изменено с bar на baz». Для этого мне нужен способсравните все свойства «до» и «после» struct и обратите внимание на различия.

 public List<string> Compare(TimeF1_MsgDayFmt original, TimeF1_MsgDayFmt new)
  

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

Как бы я подошел к этому?

Комментарии:

1. Является ли генерация кода этих структур табу?

2. @sixlettervariables Не обязательно. Я видел несколько примеров, подобных этому , где генерируется прокси-объект, но я пока не смог разобраться в этом.

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

4. @IraBaxter: Я не уверен, что вы имеете в виду. Файлы данных очень большие; время проверки одной структуры может быть не особенно значимым, но если их миллионы…

5. @IraBaxter: Должна ли эта программа «проверять» структуры? Почему? Потому что они могут быть недопустимыми в исходном файле данных. Разве у вас нет отдельного инструмента для проверки структур? Это инструмент, который я создаю. Возможно, вы имеете в виду, что у вас есть миллионы экземпляров небольшого числа типов. Да, это то, что я имею в виду. Я добавил немного больше разъяснений к началу своего вопроса.

Ответ №1:

Если проблема заключается в том, соответствуют ли данные, считываемые в структуру, дополнительным ограничениям, вам прежде всего нужно выяснить, как записать такие ограничения. (В вашем примере вы написали [ValidateRange(0,9)] в качестве одного из таких ограничений).

Как только у вас есть средство для записи ограничений, вам, предположительно, нужно прочитать данные в соответствующую структуру, а затем проверить ограничения. (В вашем примере вы предложили идею использования отражения).

Мне кажется, что самый простой способ записать такие ограничения, которые выполняются быстро, — это просто записать их как дополнительный код C #. Для каждого ограничения, которое вы можете себе представить, вы можете добавить метод класса, который проверяет ограничение и возвращает логическое значение. Вы можете добавить стандартное ограничение «CheckIt», которое вычисляет объединение всех отдельных методов ограничения.

Должно быть легко написать ограничения. Я бы ожидал, что компилятор C # встроит другие методы, особенно если они маленькие и не принимают аргументов (кроме подразумеваемого класса). Это должно ускорить их.

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

Комментарии:

1. Да, к такому выводу я тоже приближаюсь. Я думаю, что нашел решение проблемы производительности отражения, смотрите Здесь: fasterflect.codeplex.com , это может оказаться полезным. Проблема, с которой я сталкиваюсь, заключается в краткости кода; с протоколированием, сбором результатов проверки и делегатом / событием, необходимым для обновления основного пользовательского интерфейса, каждый метод проверки будет содержать более 6 строк кода. Я надеялся получить больше, чем одну строку кода для каждого ограничения. Я могу добавить метод Assert в свой класс ведения журнала, который принимает a Func<bool> , и позволить моему регистратору обрабатывать все это.