King Fisher Ответов: 2

Где экземпляр должен быть создан в контроллере web api


В контроллере веб-API, я использовал, чтобы создать экземпляр в using keyword, так что как только он выйдет из using, GC будет вызван и память будет освобождена.

Код, который я использую прямо сейчас,
public class TemplateController : AutoVHCBaseApiController
    {

        [Route("{id}")]
        [HttpGet]
        [ResponseType(typeof(VHC.Core.Common.Beans.CheckTemplate))]
        public IHttpActionResult Get(int id)
        {
            try
            {
                using(ITemplateManager manager=new   TemplateManager())
                {
                    CheckTemplate checkTemplate = manager.GetCheckTemplate(id, SiteCode);
                    return Ok(checkTemplate);
                }
            }
            catch (ValidationException ex)
            {
                return BadRequest(ex.Message, FailureReason.ReasonCodeOptions.ValidationError);
            }
        }
    }


Один из моих коллег попросил меня изменить как показано ниже:

public class TemplateController : AutoVHCBaseApiController
    {
        private readonly ITemplateManager manager;
        public TemplateController()
        {
            manager = new TemplateManager();
        }

        [Route("{id}")]
        [HttpGet]
        [ResponseType(typeof(VHC.Core.Common.Beans.CheckTemplate))]
        public IHttpActionResult Get(int id)
        {
            try
            {
                CheckTemplate checkTemplate = manager.GetCheckTemplate(id, SiteCode);
                return Ok(checkTemplate);
            }
            catch (ValidationException ex)
            {
                return BadRequest(ex.Message, FailureReason.ReasonCodeOptions.ValidationError);
            }
        }
    }


Что я уже пробовал:

Почему я должен создавать экземпляр в constuctor?
В чем разница между обоими кодами для создания экземпляра?

2 Ответов

Рейтинг:
16

F-ES Sitecore

Прежде всего, использование не делает то, что вы думаете, оно просто вызывает для вас метод dispose в конце блока, оно не освобождает память, это происходит только при запуске GC, но это вполне может означать память восстанавливается раньше. Когда вам нужно использовать using, зависит от того, какие ресурсы использует объект. Если объект использует ресурсы, не контролируемые .net (например, соединения с базой данных, сетевые соединения, файлы на диске и т. Д.), Вызов Dispose как можно раньше освободит эти ресурсы как можно скорее (при условии, что объект написан правильно) как. net не может контролировать их время жизни. Если вы не удалили объект явно, внешний ресурс останется до тех пор, пока сборщик мусора не вызовет Dispose. Поэтому, если TemplateManager не держит открытыми ресурсы, отличные от .NET, до тех пор, пока он не будет удален, тогда нет необходимости использовать "using".

Что касается конструктора и метода, здесь есть два аспекта. Если вы создаете объект в конструкторе, тогда все методы могут использовать «менеджер», зная, что переменная действительно указывает на экземпляр TemplateManager, и если три разных метода используют объект, то создается только один, а не каждый метод создает свой собственный. С точки зрения производительности это важно, поскольку одним из самых больших потерь производительности является выделение и освобождение памяти, что и делает создание объектов. Второй аспект создания объекта в конструкторе заключается в том, что если вы используете внедрение зависимостей (либо потому, что это шаблон, который вы хотите использовать, либо потому, что вы хотите начать модульное тестирование), то зависимости вводятся через конструктор, поэтому будет минимальное количество изменения в вашем коде, это будет выглядеть примерно так

public TemplateController() : this (new TemplateManager())
{
}

public TemplateController(ITemplateManager templateManager)
{
    manager = new templateManager;
}


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

Очевидно, что все это предполагает, что TemplateManager *является* многоразовым, что это нормально создавать один раз и использовать много раз, если это не так, то создание его в конструкторе-это неправильно, и код должен быть оставлен таким, как он был,


Рейтинг:
0

Afzaal Ahmad Zeeshan

Того, что вы писали, было более чем достаточно, прежде чем я скажу что-нибудь еще, нет также никакой необходимости делать это readonly, поскольку вы просто используете его для доступа к данным, а не для изменения их значений (даже во втором коде).

Теперь, как вы уже сказали, использование блока эффективно, поскольку он очищает ресурсы, как только объект выходит из области видимости. Поэтому я бы предпочел использовать этот блок using вместо того, чтобы создавать экземпляр и затем обращаться к нему в функции. Есть некоторые случаи, когда вам может понадобиться использовать этот подход, например,

public class TemplateController : AutoVHCBaseApiController
    {
        private readonly ITemplateManager manager;
        public TemplateController()
        {
            manager = new TemplateManager();
        }

        [Route("{id}")]
        [HttpGet]
        [ResponseType(typeof(VHC.Core.Common.Beans.CheckTemplate))]
        public IHttpActionResult Get(int id)
        {
            try
            {
                CheckTemplate checkTemplate = Process(args);
                return Ok(checkTemplate);
            }
            catch (ValidationException ex)
            {
                return BadRequest(ex.Message, FailureReason.ReasonCodeOptions.ValidationError);
            }

            // Clean up resources
            manager.Dispose();
        }

        // Notice I have a new function
        private CheckTemplate Process(params list) {
            // Use manager here.
        }
    }


1.вам нужно получить доступ к одному и тому же экземпляру для нескольких функций — при условии, что вы не хотите полагаться на передачу параметров.
2. создание экземпляра несколько раз имеет перегрузку или задержку-загрузка диска и т. д. — В таких случаях вы можете определить один экземпляр, а затем получить доступ к его состояниям и функциям.
3. создание экземпляра объекта является избыточным во всех обработчиках методов, и вы можете минимизировать код или реализовать сухое правило, сделав это.
4. Синглтонный паттерн — но у него есть и другие реализации, даже те, которые требуют от вас не ограничивать себя.
5. ваш босс хочет, чтобы вы это сделали.

Даже если это так, то вы наверняка можете сделать следующее,
public class TemplateController : AutoVHCBaseApiController
    {
        private ITemplateManager manager;
        public TemplateController()
        {
            // Not required anymore.
            manager = new TemplateManager();
        }

        [Route("{id}")]
        [HttpGet]
        [ResponseType(typeof(VHC.Core.Common.Beans.CheckTemplate))]
        public IHttpActionResult Get(int id)
        {
            try
            {
                // Apply using over a property. 
                using (manager = new TemplateManager()) {
                    CheckTemplate checkTemplate = Process(args);
                    return Ok(checkTemplate);
                }
            }
            catch (ValidationException ex)
            {
                return BadRequest(ex.Message, FailureReason.ReasonCodeOptions.ValidationError);
            }
        }

        // Notice I have a new function
        private CheckTemplate Process(params list) {
            // Use manager here.
        }
    }

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

Для меня сделать это изменение было неплохой идеей, но сделать это readonly и создание экземпляра в конструкторе было плохим подходом — он будет создан для POST, PUT просит тоже, даже если это не требуется.