C
C#2mo ago
Vortac

Dependency Injection Question

I'm working on a music player which can play both local and streamed media. To play the files, I'm using a library which has a SoundPlayer class. (https://lsxprime.github.io/soundflow-docs/getting-started/) To handle file vs streaming, I'm using a switch statement inside my SoundEngine class:
switch (fileType)
{
case eFileType.File:
_player = new SoundPlayer(new StreamDataProvider(File.OpenRead((string)path)));
break;

case eFileType.Stream:
_player = new SoundPlayer(new StreamDataProvider((Stream)path));
break;
switch (fileType)
{
case eFileType.File:
_player = new SoundPlayer(new StreamDataProvider(File.OpenRead((string)path)));
break;

case eFileType.Stream:
_player = new SoundPlayer(new StreamDataProvider((Stream)path));
break;
I shouldn't be newing up classes inside my SoundEngine, and want to use DI instead. However, since a user can play different files while the (which must be passed into the _player variable), I can't use constructor injection. Is there another way to handle this?
SoundFlow Documentation
Getting Started with SoundFlow
Learn how to install the library, set up your development environment, and write your first SoundFlow application.
25 Replies
Keswiik
Keswiik2mo ago
can you show more of your codebase? hard to really tell what's going on if all we can see is a switch statement
Vortac
VortacOP2mo ago
Here's my SoundEngine class: https://paste.mozilla.org/PUT8LaoC and my Program.cs: https://paste.mozilla.org/NziKCgHZ SoundEngine is accessed from a Terminal user interface controlled by a class called Tui https://paste.mozilla.org/k6fzaXZs
Keswiik
Keswiik2mo ago
personally, I think I'd change Play to take a Stream and not an object and if you want di, you can then create a SoundPlayerFactory with a public SoundPlayer Generate(Stream source) {...} method don't know what ePlayerStatus and eFileType are, but using lower case values to start type names doesn't follow normal c# conventions
Vortac
VortacOP2mo ago
Enums
Keswiik
Keswiik2mo ago
also, is there a reason you need your own player status enum? why not expose the PlaybackState of your sound player? it would let you simplify your PlayPause function to do something like:
switch (_player.PlaybackState)
{
case PlaybackState.Playing:
_player.Pause();
break;
case PlaybackState.Paused:
case PlaybackState.Stopped:
_player.Play();
break;
default:
throw new ArgumentOutOfRangeException();
}
switch (_player.PlaybackState)
{
case PlaybackState.Playing:
_player.Pause();
break;
case PlaybackState.Paused:
case PlaybackState.Stopped:
_player.Play();
break;
default:
throw new ArgumentOutOfRangeException();
}
Vortac
VortacOP2mo ago
How can I expose the playback state to the UI? Right now, my UI class takes an IPlayer instance, with SoundEngine being the implementation. The actual player is a third-party library initialized inside SoundEngine I created the enum so I could manage the playbackstate from my UI
Keswiik
Keswiik2mo ago
you could use a nullable PlaybackState property like
public PlaybackState? PlaybackState => _player?.PlaybackState
public PlaybackState? PlaybackState => _player?.PlaybackState
granted there are downsides to an approach like this if you ever change sound libraries you may have to refactor parts of your UI but if that is not an issue you could use to above to keep things simple the added benefit that a null PlaybackState would let you know that you have not attempted to play any files and could accurately show that in your UI
Vortac
VortacOP2mo ago
I'd like to try and keep the UI separate from the implementation
Keswiik
Keswiik2mo ago
in that case, you can still simplify your playback logic a little by using a fallthrough like I am
Vortac
VortacOP2mo ago
I'm getting an unexpected token on the nullable ? and a Cannot resolve symbol '_player' error
Keswiik
Keswiik2mo ago
are you using an older version of c#?
Vortac
VortacOP2mo ago
.NET 8.0
Keswiik
Keswiik2mo ago
show code then, should be valid unless you messed up syntax somewhere
Vortac
VortacOP2mo ago
private readonly MiniAudioEngine _soundEngine;
private SoundPlayer _player;
public string LastFileOpened { get; set; }

public PlaybackState? => _player?.PlaybackState;
private readonly MiniAudioEngine _soundEngine;
private SoundPlayer _player;
public string LastFileOpened { get; set; }

public PlaybackState? => _player?.PlaybackState;
Keswiik
Keswiik2mo ago
oh im dumb, made a typo in my example lol PlaybackState? PlaybackState i gave you a property with a missing name :PatrickDab:
Vortac
VortacOP2mo ago
Ahh, thank you! On the switch statement, I'm getting a cannot resolve error on PlaybackState
switch (_player.PlaybackState)
switch (_player.PlaybackState)
Keswiik
Keswiik2mo ago
change it to State https://github.com/LSXPrime/SoundFlow/blob/master/Src/Components/SoundPlayer.cs it's an open source project so you can always look at the classes and see what you can use
Vortac
VortacOP2mo ago
I had tried that, but then the switch case doesn't work:
case PlaybackState.Playing:
case PlaybackState.Playing:
Saying it cannot resolve symbol
Keswiik
Keswiik2mo ago
https://github.com/LSXPrime/SoundFlow/blob/master/Src/Enums/PlaybackState.cs it's a public type, should be able to use it make sure you're not missing a using statement for it
Vortac
VortacOP2mo ago
Another thing is to access it inside my UI, it seems I need to modify my ISoundEngine interface to add
PlaybackState PlaybackState { get; }
PlaybackState PlaybackState { get; }
Which adds a dependency on SoundFlow to my Interface. Shouldn't I try to avoid that?
MODiX
MODiX2mo ago
Vortac
I'd like to try and keep the UI separate from the implementation
Quoted by
React with ❌ to remove this embed.
Keswiik
Keswiik2mo ago
probably, but you were asking about how to use PlaybackState so i answered you can still use your own enum with the switch statement i showed just make sure you update your state property as well
Vortac
VortacOP2mo ago
I'm confused. My original switch statement used my own enum, which kept the implementation separate
Keswiik
Keswiik2mo ago
yes, and I made suggestions before you mentioned wanting to keep implementations separate my switch statement was intended to show you how to avoid copy-pasting code between cases my switch statement with fallthrough, using your enum, would look like this:
switch (WhateverYourStatusPropertyIs)
{
case ePlayerStatus.Playing:
_player.Pause();
// update WhateverYourStatusPropertyIs
break;
case ePlayerStatus.Paused:
case ePlayerStatus.Stopped:
_player.Play();
// update WhateverYourStatusPropertyIs
break;
default:
throw new ArgumentOutOfRangeException();
}
switch (WhateverYourStatusPropertyIs)
{
case ePlayerStatus.Playing:
_player.Pause();
// update WhateverYourStatusPropertyIs
break;
case ePlayerStatus.Paused:
case ePlayerStatus.Stopped:
_player.Play();
// update WhateverYourStatusPropertyIs
break;
default:
throw new ArgumentOutOfRangeException();
}
Vortac
VortacOP2mo ago
Thanks!

Did you find this page helpful?