简体   繁体   中英

Dependency injection of multiple Rx subjects in c# / .net core

I have the following scenario in a .net core C# application:

Service A -> Subject<Foo> -> Service B Service C -> Subject<Foo> -> Service D

The two instances of Subject<Foo> have different semantics, so they need to be different instances. Lets assume the first subject delivers "awesome" Foo s, the second delivers "great" Foo s.

Service A has a dependency to Subject<Foo> as well as Service B. Now, I'd like to use the dependency injection that ships with dotnet core to add two instances of the Subject<Foo> to the container so that all services can be constructed with the subjects they depend on (A and B depend on the first instance, C and D on the second).

My first idea was to create derived interfaces IFooFirstSubject : ISubject<Foo> and IFooSecondSubject : ISubject<Foo> :

services.AddSingleton<IFooFirstSubject>( HOW TO GET A FooFirstSubject Instance?! ); services.AddSingleton<IFooSecondSubject>( HOW TO GET A FooSecondSubject Instance?! );

However, now I need a concrete Subject implementation that implements the IFooFirstSubject interface. One idea was to subclass Subject and implement the marker interface but Subject is a sealed class. I currently see three approaches and I'm not happy with either:

1) Instead of making A und B depended on the subject, create a SubjectRegister concrete class, from which A,B,C,D can query the subject they want like subjectRegister.FooFirstSubject . Having the register in between seems like a smell to me.

2) Use the adapter pattern to solve the sealed class issue. FooFirstSubject could then implement IFooFirstSubject and use (not derive from) a Subject . That seems like a whole lot of work if I have many subjects between my services.

3) There might be a way to add the marker interface using reflection. Which also feels like I am doing something that is not meant to be done.

In essense: Is there another way (maybe I am even using the wrong class with Subject here?) to achieve what I am trying to do?

Edit: I created a lengthy explanation on the why and what i am trying to accomplish here (due to the many comments, thanks for them!): https://gist.github.com/anonymous/e933846c2c8e213128a49a2a6f8f7154

Just register an instance of the concrete implementation. Interfaces are good but not strictly necessary.

services.AddSingleton(new Subject<Foo>());

The thing is, dependency injection works on types and if there are two instances of the exact same type, then there's no way with DI to disambiguate between those two. At least unless you use keyed dependencies which are not available in Microsoft.Extensions.DependencyInjection and which could be a sign for a bad design .

You should think about whether you really need separate subjects here. The way I understood your situation (and going by that more concrete tweet-based example), you are using the subject to publish events about that Foo object. And you need two different subjects because you have two different events that you want different components to subscribe to.

So you actually have different event types , which suggests that instead of having subjects about the event target , you should have subjects about the events instead. So you would have a Subject<AwesomeFooDelivered> and a Subject<GreatFooDelivered> . Both events would then have a reference to the actual Foo but that way components could subscribe to the actual event instead of the object which had something happen to it.

With your SO Q/A question example, this would make this Subject<QuestionPosted> and Subject<QuestionUpvoted> ; and with your tweet example you would have Subject<TweetReceived> and Subject<HashtagDiscovered> .

By having subjects on the events, you could easily have multiple components subscribe to the same event subject, and have multiple components independently subscribe to the events. So this would allow you true decoupling.

And since the subjects are now of different types, you also wouldn't have a problem registered them as dependencies, and components depending on them would again be clear about what they actually depend on, making your architecture more clear.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM