使用方法进行类实例化的速度有多快,但没有字段或属性?

时间:2012-03-13 20:20:01

标签: c# .net asp.net-mvc dependency-injection service-locator

一般情况下,使用方法但没有字段或属性的类的实例化会有很多开销吗?

我正在开发一个大量使用构造函数注入的ASP.NET MVC应用程序,到目前为止,一些控制器最多有10个依赖项。但是由于依赖性很大,我使用IMyAppServiceProvider接口和类,通过MVC 3中的DependencyResolver提供对所有依赖项的泛型访问。

我删除了所有特定于应用程序的代码,并使用我的基本设置创建了Gist(这不包括下面提到的BaseController设置)。

我还创建了一个接受IMyAppServiceProvider的BaseController类。所有控制器都继承自此基类。基类采用IMyAppServiceProvider对象,并为所有各种服务提供受保护的变量。代码看起来像这样:

public class BaseController
{
    protected IService1 _service1;
    protected IService2 _service2;
    protected IService3 _service3;
    // ...

    public BaseController(IMyAppServiceProvider serviceProvider)
    {
        _service1 = serviceProvider.GetService<IService1>;
        _service2 = serviceProvider.GetService<IService2>;
        _service3 = serviceProvider.GetService<IService3>;
        // ...
    }
}

这使控制器的代码“吱吱作响”。没有私有/受保护的变量,构造函数中没有赋值,服务由基类保护变量引用。 但是,每个请求都会实例化我的应用程序使用的每个服务,无论特定控制器是否使用所有这些服务。

我的服务很简单,只包含带有一些业务逻辑和数据库交互的方法调用。他们是无国籍人,没有阶级领域或财产。因此,实例化应该很快,但我想知道这是否是最佳实践(我知道这是一个加载的术语)。

2 个答案:

答案 0 :(得分:7)

  

每个请求都会实例化我的每一项服务   应用程序使用,无论特定控制器是否使用全部   它们。

我相信你自己已经回答了你的问题,这不是一个好方法。 此外,使用这种依赖性解析(Service Locator注入)是一种不好的做法,因为Controller的API变得混乱。控制器客户端不知道特定控制器真正需要哪些服务,因此最终可能会出现意外的运行时错误,单元测试也会变得一团糟。

BTW还有一个建议 - 通过abstract关键字标记所有被认为是基类的类,这样就可以避免将它用作具体类。设计和实现基类是一个具体的设计决策,因此要明确您的设计意图。

关于实例化的成本,在你的情况下它不会产生很大的不同,但一般来说,为了降低重型对象实例化的成本,你可以:

  • 使用Prototype pattern “避免以标准方式创建新对象的固有成本(例如,使用'new'关键字),当它对于给定的应用程序来说过于昂贵时”(c)Wikipedia
  • 使用Lazy Initialization用于从所有者对象生命周期开始时不需要的服务,因此这些服务将按需初始化。由于.NET Framework 4.0可以使用内置的Lazy(T) class

答案 1 :(得分:2)

我认为您在这里寻找的解决方案是使用自定义控制器工厂。这样,创建的每个控制器都具有所需的依赖关系。这是StructureMap的一个,来自weblogs.asp.net

using StructureMap; 
public class StructureMapControllerFactory : DefaultControllerFactory { 

    protected override IController GetControllerInstance(Type controllerType) {
        try {
           return ObjectFactory.GetInstance(controllerType) as Controller;
        }
        catch (StructureMapException) {
            System.Diagnostics.Debug.WriteLine(ObjectFactory.WhatDoIHave());
            throw;
        }
    }
}

protected void Application_Start() {
    RegisterRoutes(RouteTable.Routes);

    //Configure StructureMapConfiguration
    // TODO: config structuremap        

    //Set current Controller factory as StructureMapControllerFactory
    ControllerBuilder.Current.SetControllerFactory(new StructureMapControllerFactory()); 
}