Использование IDisposable + таймер для измерения прошедшего времени - PullRequest
0 голосов
/ 13 апреля 2019

У меня есть код, который выполняет много работы.Он выполняет достаточно работы в течение достаточного времени, поэтому мы не заботимся о точной точности (например, с точностью до миллисекунды), но отключение более чем на минуту не будет полезным.У нас есть хранимая процедура, которую мы вызываем для регистрации начала задачи и конца задачи.Прямо сейчас у нас есть много кода, который выглядит следующим образом:

Logger.LogTaskStart(taskName);
// do stuff
Logger.LogTaskEnd(taskName);

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

if (debug) Logger.LogTaskStart(taskName);
// do stuff
if (debug) Logger.LogTaskEnd(taskName);

У нас были проблемыгде мы непреднамеренно не совпадаем с началом и концом, или мы помещаем только один под флагом отладки и т. д. Мы рассмотрели создание довольно простого класса логгера, который реализует IDisposable, чтобы сделать это для нас, так, чтобы мы просто делали это (предположим,что конструктор запускает стиль таймера RAII и что Dispose останавливает его)

using (new Logger(taskName, debug))
{
    // Do stuff
}

Как можно лучше сказать, это должно скомпилироваться примерно так:

Logger loggerThing = null;
try
{
    loggerThing = new Logger(taskName, debug);
    // Do stuff
}
finally
{
    loggerThing?.Dispose();
}

Как таковойкажется, довольно безопасно использовать это для наших больших задач с достаточной степенью детализации, чтобы можно было сказать, «что прошло достаточно много времени» или «что выполнялось значительно быстрее / медленнее, чем обычно».Мы правы?

Из некоторого прочтения я обнаружил следующие статьи, примеры кода и SO Q & A.Ясно, что мы не единственные, кто задумывался об этом или о чем-то подобном, но никто, кажется, никогда не давал ясного и окончательного ответа на вопрос «насколько мы можем предположить, что Dispose будет называться, и насколько надежным будетСроки результатов этого будут?Учитывая первый пост ниже, относительно того, как using является просто синтаксическим сахаром, мы склонны думать, что это так.

1 Ответ

0 голосов
/ 13 апреля 2019

Метод Dispose вызывается сразу после кода в операторе using. Чтобы подтвердить это, мы можем взглянуть на IL, сгенерированный из оператора using:

Следующий простой пример:

    class Program
    {
        static void Main()
        {
            using (new TestClass())
            {
                Console.WriteLine("Do work");

            }
        }
    }

    class TestClass : IDisposable
    {
        public void Dispose()
        {
            Console.WriteLine("disposed");
        }
    }


Создает следующий IL.

Program.Main:
IL_0000:  nop         
IL_0001:  newobj      UserQuery+TestClass..ctor
IL_0006:  stloc.0     
IL_0007:  nop         
IL_0008:  ldstr       "Do work"
IL_000D:  call        System.Console.WriteLine
IL_0012:  nop         
IL_0013:  nop         
IL_0014:  leave.s     IL_0021
IL_0016:  ldloc.0     
IL_0017:  brfalse.s   IL_0020
IL_0019:  ldloc.0     
IL_001A:  callvirt    System.IDisposable.Dispose
IL_001F:  nop         
IL_0020:  endfinally  
IL_0021:  ret         

Program..ctor:
IL_0000:  ldarg.0     
IL_0001:  call        System.Object..ctor
IL_0006:  nop         
IL_0007:  ret         

TestClass.Dispose:
IL_0000:  nop         
IL_0001:  ldstr       "disposed"
IL_0006:  call        System.Console.WriteLine
IL_000B:  nop         
IL_000C:  ret         

TestClass..ctor:
IL_0000:  ldarg.0     
IL_0001:  call        System.Object..ctor
IL_0006:  nop         
IL_0007:  ret         

Здесь мы видим, что метод dispose вызывается сразу после кода в операторе using.

...