获取没有构造函数注入的服务实例

dst*_*str 59 angular2-injection angular2-di angular

@Injectable在bootstrap中定义了一个服务.我想在不使用构造函数注入的情况下获取服务的实例.我试过使用ReflectiveInjector.resolveAndCreate但似乎创建了一个新实例.

我试图做的原因是我有一个由许多组件派生的基本组件.现在我需要访问服务,但我不想将它添加到ctor,因为我不想在所有衍生组件上注入服务.

TLDR:我需要一个 ServiceLocator.GetInstance<T>()

更新: RC5 +的更新代码:存储用于组件的进样器实例

Gün*_*uer 58

是的,ReflectiveInjector.resolveAndCreate()创建一个新的未连接的注入器实例.

您可以使用注入Angulars Injector实例并从中获取所需的实例

constructor(private injector:Injector) {
  injector.get(MyService);
}
Run Code Online (Sandbox Code Playgroud)

您还可以存储Injector一些全局变量,然后使用此注入器实例来获取提供的实例,例如https://github.com/angular/angular/issues/4112#issuecomment-153811572中所述.

  • 问题是没有构造函数,这使得这个答案相当无益. (32认同)
  • @Rhyous魔术?您可以在静态字段或全局变量中共享注入器,然后从那里访问它,但是首先您需要使用构造函数在某个位置注入它,并将其分配给静态域。 (2认同)
  • 这不是基本功能,而是代码味道。 (2认同)

小智 29

在使用ngModules的更新的Angular中,您可以在代码中的任何位置创建可用的变量:

export let AppInjector: Injector;

export class AppModule {
  constructor(private injector: Injector) {
    AppInjector = this.injector;
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 哇我们可以这样做吗? (3认同)
  • 是的,让一切都成为一个全局公共静态整体变量。不是 (3认同)
  • 你是国王! (2认同)
  • 这有一个小问题。您必须为提供服务的延迟加载模块制作单独的注入器。 (2认同)

Thi*_*ier 5

另一种方法是定义一个自定义装饰器(CustomInjectable用于为依赖项注入设置元数据:

export function CustomComponent(annotation: any) {
  return function (target: Function) {

    // DI configuration
    var parentTarget = Object.getPrototypeOf(target.prototype).constructor;
    var parentAnnotations = Reflect.getMetadata('design:paramtypes', parentTarget);

    Reflect.defineMetadata('design:paramtypes', parentAnnotations, target);

    // Component annotations / metadata
    var annotations = Reflect.getOwnMetadata('annotations', target);
    annotations = annotations || [];
    annotations.push(annotation);
    Reflect.defineMetadata('annotations', annotations, target);
  }
}
Run Code Online (Sandbox Code Playgroud)

它将利用来自父构造函数的元数据,而不是其自身的元数据。您可以在子类上使用它:

@Injectable()
export class SomeService {
  constructor(protected http:Http) {
  }
}

@Component()
export class BaseComponent {
  constructor(private service:SomeService) {
  }
}

@CustomComponent({
  (...)
})
export class TestComponent extends BaseComponent {
  constructor() {
    super(arguments);
  }

  test() {
    console.log('http = '+this.http);
  }
}
Run Code Online (Sandbox Code Playgroud)

有关更多详细信息,请参见此问题:

  • 问题是tsc不允许我调用super(arguments),因为基本构造函数的参数不匹配。 (2认同)

Fla*_*ken 5

Angular 14 引入了一个inject函数。

根据文档

实际上,在构造函数、构造函数参数和字段初始值设定项中允许调用inject():

@Injectable({providedIn: 'root'})
export class Car {
  radio: Radio|undefined;
  // OK: field initializer
  spareTyre = inject(Tyre);

  constructor() {
    // OK: constructor body
    this.radio = inject(Radio);
  }
}
Run Code Online (Sandbox Code Playgroud)

从提供者的工厂调用注入也是合法的:

providers: [
  {provide: Car, useFactory: () => {
    // OK: a class factory
    const engine = inject(Engine);
    return new Car(engine);
  }}
]
Run Code Online (Sandbox Code Playgroud)

因此,在您的情况下,您可以使用

class MyClass {
serviceLocator = inject(ServiceLocator)
}
Run Code Online (Sandbox Code Playgroud)