IDisposable GC.SuppressFinalize (это) местоположение

У Луа нет способа узнать, когда или где был представлен глобал.

В частности, что значение является функцией, debug.getinfo может помочь, сообщив вам, где определена функция (что часто, но не всегда, является тем же местом, где функция делается глобальной).

Вы можете получить необходимую информацию во время представления глобала. Это может быть сделано путем установки метатаблицы с помощью метода __newindex в глобальной таблице. Этот метод будет вызываться, когда вводится новый глобал (но не тогда, когда существующий глобал переопределяется). В этом методе вы можете выяснить, откуда пришел вызывающий с debug.getinfo. Также будьте осторожны, если любой другой ваш код пытается использовать метатаблицу в глобальной среде, вы должны хорошо с ней поиграть. (Он может иметь только одну метатаблицу.)

Вы также можете избежать использования глобальной таблицы. Один из промежуточных способов сделать это - переопределить окружение. В Lua 5.2 и Lua 5.3 это делается путем объявления локальной таблицы с именем _ENV - вместо этого все обращения к глобальной таблице будут иметь доступ к этой таблице. (На самом деле, глобальные доступы всегда используют _ENV и _ENV по умолчанию _G.) Вы можете сделать это главным образом невидимым, предоставив метатаблице _ENV, которая перенаправляет доступ к _G (или любой другой среде). Разница здесь в том, что __newindex будет по-прежнему вызываться, даже если в _G существует привязка, поэтому этот метод может обнаруживать переопределения.

Использование _ENV, хотя по своей природе является локальным для области (например, каждый файл должен переопределять его). Такой крюк может быть установлен и во всем мире. Если вы загружаете свои модули вручную с помощью функции load (маловероятно), вы можете просто предоставить пользовательский _ENV в качестве аргумента. Если вы используете require, можно получить удержание загруженного файла перед его выполнением, переопределив (или установив патчи) поиск Lua в package.searchers[2]. Это встроенная функция, которую require вызывает, чтобы найти файл в вашей файловой системе и затем загрузить его. Возвращаемым значением является загруженная функция, которая затем запускается require. Таким образом, после загрузки, но до возвращения обратно в require, вы можете использовать debug.setupvalue для переопределения значения по умолчанию _ENV (если есть).

Пример кода (только слегка проверенный):

local global_info = {}

local default_searcher2 = package.searchers[2]

package.searchers[2] = function(...)
  local result = default_searcher2(...)
  local parent_environment = _G
  local my_env = setmetatable({}, {
    __index = parent_environment,
    __newindex = function(self, k, v)
      local new_info = debug.getinfo(2)

      -- keeping rich data like this could be a memory leak
      -- if some globals are assigned repeatedly, but that
      -- may still be okay in a debugging scenario
      local history = global_info[k]
      if history == nil then
        history = {}
        global_info[k] = history
      end
      table.insert(history, {info = new_info, value = v})

      parent_environment[k] = v
    end,
  })
  if type(result) == "function" then
    debug.setupvalue(result, 1, my_env)
  end
  return result
end

function gethistory(name)
  local history = global_info[name]
  if history == nil then
    print('"' .. name .. '" has never been defined...')
  else
    print('History for "' .. name .. '":')
    for _, record in ipairs(history) do
      print(record.info.short_src .. ": " .. record.info.currentline)
    end
  end
end

Обратите внимание, что здесь ловушка будет применяться только к файлам, требуемым после запуска этого кода, и в основном применяется только к файлам Lua (не C libs) которые включаются через встроенный require. Он не устанавливает метатаблицы в глобальной среде, поэтому не конфликтует, но его можно обойти, если файлы обращаются к _G напрямую (или, например, настраивают доступ к _G вместо _ENV в своих собственных таблицах _ENV ). Такие вещи также могут быть учтены, но это может быть кроличья нора в зависимости от того, насколько «невидимым» вам нужен этот патч.

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

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

11
задан akjoshi 12 April 2012 в 06:52
поделиться

5 ответов

Я предполагаю, что это - очевидный случай Шаблонного Шаблона разработки.

Ваш абстрактный класс Разработан для заботы обо всех важных/необходимых требуемых задачах (Здесь, GC.SuppressFinalize (это)), и разрешение производного класса переопределить только некоторую часть кода.

Здесь существует 2 случая:
Отрывок 1, SuppressFinalize, в располагает
Отрывок 2, SuppressFinalize, в располагает (верный)

Здесь, Отрывок 1, удостоверяется, что GC.SuppressFinalize всегда выполняется. В то время как отрывок 2, оставляет выполнение GC.SuppressFinalize во власти производного класса.

Так, путем помещения GC.SuppressFinalize, в Располагают метод, Вы как разработчик Вашего класса будете всегда удостоверяться, что независимо от любого кода, написанного производными классами, GC.SuppressFinalize будет выполняться.

Это - только преимущество записи, что SuppressFinalize в Располагают, скорее затем Располагают (верный).

12
ответ дан 3 December 2019 в 06:23
поделиться

Я думаю, что любое расположение, возможно, было выбрано, но вероятно они хотели подчеркнуть "помещенный, весь код освобождения в этом методе" в защищенном Располагает метод, таким образом, они помещают другой артефакт расположения (Подавляющий завершение) в другом месте.

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

1
ответ дан 3 December 2019 в 06:23
поделиться

Dispose(bool isDisposing) метод не является частью IDisposable интерфейс.

Вы обычно звонили бы Dispose(true) от Вашего Dispose метод и вызов Dispose(false) от Вашего финализатора, как нейтрализация в случае, где объект не был уже расположен.

Вызов SuppressFinalize говорит GC, что нет никакой потребности назвать финализатор Вашего объекта, по-видимому, потому что вся Ваша очистка была сделана когда Dispose был назван.

Если у Вас нет финализатора на Вашем классе, то Вы не должны звонить SuppressFinalize вообще с тех пор нет никакого финализатора для подавления!

У Joe Duffy есть некоторые большие инструкции по распоряжению, завершению, сборке "мусора" и т.д.

5
ответ дан 3 December 2019 в 06:23
поделиться

Идея состоит в том, что Ваш код очистки нужно только назвать однажды. Однако существует две точки входа: Dispose метод и объектные финализаторы. Когда Dispose назван, Вы уклонение завершения так, чтобы Ваш код очистки только назвали однажды. Код здесь мог бы проиллюстрировать его лучше.

Кавычка:

// NOTE: Leave out the finalizer altogether if this class doesn't 
// own unmanaged resources itself, but leave the other methods
// exactly as they are. 
0
ответ дан 3 December 2019 в 06:23
поделиться

Причина.Dispose состоит в том, когда управляемый код (Ваш код) избавляется от объекта, таким образом, выбирая из завершения. Люди обычно создают другой маршрут в, Располагают (bool располагающий) через финализатор, и вызов не имел бы никакого смысла для финализатора делать.

1
ответ дан 3 December 2019 в 06:23
поделиться
Другие вопросы по тегам:

Похожие вопросы: