Angular DI and inheritance: injecting extensions of a base service

安稳与你 提交于 2019-12-29 01:52:10

问题


I have a base service and two inhering services:

@Injectable({ providedIn: 'root' })
export class BaseService {
  foo(src?: string){
    return `speaking from ${src || 'BaseService'}`;
  }
}


@Injectable({ providedIn: 'root' })
export class SomeService extends BaseService {
  foo(){
    return super.foo('SomeService')
  }
}

@Injectable({ providedIn: 'root' })
export class AnotherService extends BaseService {
  foo(){
    return super.foo('AnotherService')
  }
}

I wish to inject them in some component and retrieve instances of the three separate classes:

@Component({
    selector: 'my-app',
    template: `
        <div>
            <p>Who's there?</p>
            <p>{{ base }}</p>
            <p>{{ some }}</p>
            <p>{{ another }}</p>

        </div>
    `,
})
export class App {
    base: string;
    some: string;
    another: string;

    constructor(base: BaseService, some: SomeService, another: AnotherService) {
        this.base = base.foo();
        this.some = some.foo();
        this.another = another.foo();

    }
}

Instead, I get three instances of the same class (HTML output):

Who's there?

speaking from BaseService

speaking from BaseService

speaking from BaseService
  • Why doesn't this work?
  • Why are SomeService, AnotherService and BaseService not unique tokens for Angular DI?

It seems that putting

...    
{ provide: SomeService , useClass: SomeService },
{ provide: AnotherService , useClass: AnotherService },
...

in the providers will make it work.

  • Why is this explicitly needed?

A plnkr: https://next.plnkr.co/edit/BvmppLHRbFbz9CFZ


回答1:


SomeService and AnotherService inherit the decorator metadata from BaseService, so angular injects an instance of BaseService in their place.

This is dangerous, as calling any instance member from either SomeService or AnotherService which isnt inherited from BaseService will trigger a run-time error.

The simplest way to archive the behavior you are looking for, would be to inherit from a common abstract base class, with no decorator:

export abstract class AbstractBaseService {
  foo(src?: string) {
    return `speaking from ${src || 'AbstractBaseService'}`;
  }
}

@Injectable({ providedIn: 'root' })
export class BaseService extends AbstractBaseService {
  foo() {
    return super.foo('BaseService');
  }
}

@Injectable({ providedIn: 'root'})
export class SomeService extends AbstractBaseService {
  foo() {
    return super.foo('SomeService');
  }
}

@Injectable({ providedIn: 'root' })
export class AnotherService extends AbstractBaseService {
  foo() {
    return super.foo('AnotherService');
  }
}

I modified your plnkr to test this approach.



来源:https://stackoverflow.com/questions/52455303/angular-di-and-inheritance-injecting-extensions-of-a-base-service

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!