I'm developing a platformer using C# and monogame as a fun project to improve my skills. I want to add support for settings like audio, video, controls and more but I don't know the best way to do so.
I plan on having a XML file that stores all settings kind of like this:
<Settings>
<Audio>
<masterVolume>100</masterVolume>
<musicVolume>40</musicVolume>
<sfxVolume>90</sfxVolume>
</Audio>
<Video>
<Resolution>
<width>1920</width>
<height>1080</height>
</Resolution>
</Video>
<Controls>
<forward>W</forward>
<back>S</back>
<left>A</left>
<right>D</right>
</Controls>
</Settings>
My plan was to use a Settings class that has static variables for audio, video and controls etc that are divided into separate classes so that I can access them through Settings.Audio.MasterVolume or Settings.Controls.Forward.
I want to load the settings into these classes from the XML using Linq and I want to save the settings to the XML file when they are changed by the user.
I know that singletons can be used as well but as far as I can tell from the research I've done it has too many drawbacks. Is that true?
Is this a good way to do this or is there a better way that allows me to access the settings throughout the project without having everything static?
Thanks in advance!
Your method works. However, you limit the re-usage of your class.
If you would describe MyClass to others, would you say that the method being used to read the configuration parameters is essential for MyClass? In other words: would most code of your class be meaningless if the configuration parameters wouldn't be read from a configuration file, but for instance from a CSV-file, or from the internet, or whatever method?
You'll probably say no: most code of my class could be reused if the configuration parameters were to be provided differently.
So why limit your class to a class that can only work if it reads the configuration parameters from a configuration file?
I guess that you currently have something like:
static class ConfigurationSettings
{
public static int LeftControl => ...
public static int RighControl => ...
}
class MyClass
{
// MyClass uses configuration settings:
public int LeftControl => ConfigurationSettings.LeftControl;
public int RightControl => ConfigurationSettings.RightControl;
...
}
You can't instantiate two objects of MyClass, each with their own set of configuration parameters. You can't create a MyClass object that uses a different method of providing configuration values.
One of the use cases I quite often need this is when unit testing: I want a quick way to be able to change the configuration settings without having to change the configuration file of the unit test project.
An easy way to allow users of your class to provide different methods for setting is to create an interface with the setting and provide a constructor with this interface:
interface IMySettings
{
int LeftControl {get;}
int RightControl {get;}
...
}
class ConfigurationSettings : IMySettings
{
// ConfigurationSettings reads settings from the configuration file
}
class MyClass
{
// default constructor use the configuration file via ConfigurationSettings:
public MyClass() : this (new ConfigurationSettings())
{
}
// extra constructor for those who don't want to use configuration file
public MyClass(IMySettings settings)
{
this.Settings = settings;
}
protected readonly IMySettings settings;
// MyClass uses settings:
public int LeftControl => this.settings.LeftControl;
public int RightControl => this.settings.RightControl;
}
Users who want to use the settings from the configuration file can use the default constructors; uses who want specific settings use the alternative constructor. This alternative constructor is also used if you want two different MyClass objects, each with their own settings.
At first glance it seems that with minimal changes you can still use the configuration file. However, to be able to implement the interface, the class that reads the configuration file (MyClass) can't be static.
However, you were right: there is only one configuration file, hence there should be only one instance of the class that reads from the configuration file: create a singleton.
In my experience, classes that represent a configuration, is one of the often used reasons to use a singleton instead of a static class
In my game projects I always use some static classes (and/or variables) to hold information that is valid through the whole game.
This might come in handy especially for audio settings if you want to be able to change the volume and so on from different points of the game.
This does not necessarily only include user settings. Thinkig of lowering the background music when some character is speaking.
long story short:
I would go for the static approach. But take care not to over exceed it.
Related
what is the best way to have data accessible throughtout the wole application? In my concrete example I load the settings of my application from an XML file into an instance of a Settings-Object, and I don't want to make these some absolute constants because the user should be able to change these (and see the effects) without restarting the program.
Now, I need to use certain of the (properties of the) settings in methods of other classes, but in this way they are not accessible. So in what kind of an 'Object' should I store the settings? I don't think it is good it each method that needs a setting across my application has to look into the XML itself. Also, passing the settings instance into every other class I use seems too cumbersome.
Thanks in advance!
In C# I always use a static classes to provide this functionality. Static classes are covered in detail here, but briefly they contain only static members and are not instantiated -- essentially they are global functions and variables accessed via their class name (and namespace.)
Here is a simple example:
public static class Globals
{
public static string Name { get; set; }
public static int aNumber {get; set; }
public static List<string> onlineMembers = new List<string>();
static Globals()
{
Name = "starting name";
aNumber = 5;
}
}
Note, I'm also using a static initializer which is guaranteed to run at some point before any members or functions are used / called.
Elsewhere in your program you can simply say:
Console.WriteLine(Globals.Name);
Globals.onlineMembers.Add("Hogan");
To re-state in response to comment, static objects are only "created" once. Thus everywhere your application uses the object will be from the same location. They are by definition global. To use this object in multiple places simply reference the object name and the element you want to access.
Define some simple Configuration (say) class:
public static class Configuration
{
/*runtime properties */
public static void LoadConfiguration(..)
{
/*Load from file a configuration into the static properties of the class*/
}
public static bool SaveConfiguration(...)
{
/*Save static properties of the class into the configuration file*/
}
}
Do not forget naturally default configuration, in case when config file for some reason missed.
Hope this helps.
Sounds like a perfect use of the Settings project page. You setup defaults, they can be modified and saved between runs of your application.
You can have a static class with static properties to get and set
I have a Common project inside which I've added my public constants for QueryStringNames.
I know generally constants should be as internal or private but I'd need public constants here as I'd like to allow a global access to the query string names, session keys, etc.
There are 3 solutions that I know of but all of them have an important issue. The caller assembly would contain the copy of my constant which means if I have to change a constant value, I'll have to compile both my Common assembly and the caller assembly!
1) public const string ConstName = "a value";
2) public readonly string ConstName = "a value";
3) To be stored in a public resource file.
What would be the best approach to define public constants in C# apart from storing them in the web.config file (which doesn't have intellisense)?
It depends. If it is truly a constant that won't change, even in future versions of your code, then const is fine. Else go with a static readonly field.
A const will get embedded into the calling assembly, whereas with static readonly the calling assembly only contains a reference to the field. This means const requires recompilation of all dependent code whenever you change the value, whereas public readonly uses the new value even without recompiling the calling assembly.
If you want to store the "constant" in a config file, but like Intellisense, you can use a property with no public setter. And then fill it from the config file at runtime. But I'd argue that configuration values should not be static in the first place. For configuration values I'd use a singleton of some sort, preferably the IoC variation and not the Class.Instance variation. So I'd just define an interface like the following:
interface IMyConfig
{
string Key{get;}
}
And have classes that need this config take it as a constructor parameter:
public MyClass(IMyConfig config)
{
...
}
If you think you'd be changing it and you're worried about having to compile it, then why not use appSettings in the web config file? That's what it's for. If you really need intellisense then you could just put a class in one of the assemblies that reads the config value and exposes it as a property for easier referencing. If it's sensitive data then I wouldn't put it in a config file, I would just compile it anyways since you don't want to compromise your application.
<appSettings>
<add key="myconstant" value="here's the value!" />
</appSettings>
Here's the class to reference that value, which gives you intellisense, ability to change it easily in the future, and without having to recompile anything
public class MyAppConfigSettings
{
public string MyConstant { get; private set; }
public MyAppConfigSettings()
{
MyConstant = ConfigurationManager.AppSettings["myconst"];
}
}
It may not be the answer to your solution but it may give you some other ideas.
If you are activating fxCop (code analysis tool included in Visual studio distribution), you may get sugestion to change constant to become:
public static readonly string ConstName = "a value";
I'm not sure if I understand the problem completely... you're asking for a solution to storing some global variables that won't cause recompiles to assemblies that reference those global variables if you change them? If so then why not try thinking about redesigning your architecture as per the Inversion of Control principle? Think "don't call us, we'll call you" the hollywood principle. If all the assemblies that require some const just call an interface (that they own) that exposes a property with the value they require, and then you have a project of constants that implement those interface (by referencing those projects and then implementing those interfaces) then those projects will never need recompilling when you change the value of the constants.
I'm sure you know them anyway but have a read up on the SOLID principles, "D" being the Dependency Inversion principle (Inversion of Control). I think given your concerns (assuming I've understood you right) they could really help you out.
An example of Inversion of Control could be as simple as:
MyService.dll :
public class MyService
{
// injected dependency
public IMyConstants MyConstants { get; set; }
public MyMethod(){
// get your query...
var query = IMyConstants.Query;
}
}
MyConstants.dll :
public MyConstants : IMyConstants {
// implementation of query property from the myservices.dll interface
public string Query { ... }
}
So the myconstants.dll references the myservice.dll rather than the other way around (meaning myservices won't need recompiling). Then the bootstrapping code (to set it all up and inject dependencies) lives elsewhere.
Sorry if I misunderstood you, hope that helps though!
I prefer the 2nd option in most case since it won't cause problem (by copy value to other assemblies). The speed may have a slower than constants but this kind of nano-second speed is pretty immature.
You could use the Cache object and define them in Global.asax
As said before, it's not the same scenario:
const: is contant and cannot be modified except by recompiling.
readonly: the value is initialized in the declaration or in the constructor and stay readonly after.
When a field declaration includes a readonly modifier, assignments to the fields introduced by the declaration can only occur as part of the declaration or in a constructor in the same class
What I would like to do is have a versatile settings class that I can use in a composite application. As I add features and components and compose the application using MEF & Prism I would like to have a settings window that automatically loads the settings interface of each of the modules into a window (using Prism & MEF)
There are many different ways of dealing with settings, and the one that appeals to me is something along the following:
public class AppData : ApplicationSettingsBase
{
[UserScopedSetting()]
[DefaultSettingValue("true")]
public bool Clipboard
{
get { return ((bool)this["Clipboard"]); }
set { this["Clipboard"] = (bool)value; }
}
}
It allows me to set a default value and I am assuming that if the application does not find the .settings file then it will create one with the defaults. However I would need to write a bunch of custom code for each modules settings section and either create a unique dialog for each module or try to have a settings manager that manually loads them all in.
There are some settings that would have multiple values as well and it does not look like the above example would be able to accomodate that. What if I had a setting that stored a list of something? For example if I had a setting that was ValidBlock, and at the start there are two blocks that could be valid but in the future there may be a need to add more? Can you have a setting that is a list and specify multiple default values for that setting?
So would it be acceptable to create a Isettings interface that somehow used ApplicationSettingsBase so that I can use MEF to find all Isettings implementations in all the modules in a directory and then compose a dialog with tabs for each implementation it found? In the Isettings interface I could have some basic properties such as Name and whatever else would be needed to label and describe the module in the MEF WPF window.
The only other thing I do not like is that there are strings and attributes all over the place. Is there a way to deal with settings in a fluent way? I am thinking along the lines of having a ISettings implementation that you would explicitly code a setup something like the following:
public class AppData : ISettings
{
Setting Clipboard = new Setting();
Clipboard.Scope = SettingScope.User;
Clipboard.SettingType = List<String>;
List<String> DefaultClipboards = new List<String>();
DefaultClipboards.Add("FoxClipboard");
Clipboard.DefaultSetting = DefaultClipboards;
}
I know the above is not exactly syntax correct, and I do not think that the Clipboard.SettingType would hold much water but its to give an idea of what I am thinking. So if something like this can be achieved while maintaining the creation of a settings file in the event one is missing that would be ideal. As well with something like this MEF can find all the ISettings implementations and create a tab for each one, and then add each Setting based on setup of it in the code.
Is this the right track to be on? Is there a framework or project out there that I have missed that handles what I am aiming for? I am thinking there is probably a better way than what I have outlined?
I am sure this question has come up in composite application development but I have not found a framework or an answer that outlines this scenario.
I have been able to create a loose coupled composite application and dynamically wire up my modules using MEF & Prism but I have not been able to find a satisfactory way to deal with settings in a composite way.
I tackled something similar for one of my applications at work. We leaned further towards your second idea, where there is simply a base settings interface "ISettings" that we used for MEF composition.
We created a custom export provider to deal with loading settings, and had a manager to save out the settings using some serializer.
For the UI, we had modules with user facing settings also export a "settings workspace" that we would load into the settings UI. Using reflection, we wrote a method that will make a deep copy of a settings object so that we could do direct mvvm binding to the cloned object (for cancel functionality), as well as take an object and copy it's properties back.
The reflection was to allow for a generic clone/copy without writing code for every settings object.
Also, one thing that we did that I still love to this day for data model binding is the "INotifyPropertyChanged" interface. Our base ISettings object requires it. This allows not only the settings UI to directly bind to settings and listen for changes, but when we hit apply or ok, all of our data model that needs settings registers for the prop changed event, so they all automatically get notified when a setting has changed.
Check out Property Observer if you plan on doing the notify route. This application has been deployed and I still feel like our settings framework is wildly successful.
If you need, I can provide further detail in certain areas.
Hope this helps!
Disclaimer: I have no experience with custom implementations of ApplicationSettingsBase so I can not assist with its actual implementation, nor positively say that this approach will work. However, what I propose might be a path worth exploring if you really want to use ApplicationSettingsBase.
First of all, ISettings can not inherit ApplicationSettingsBase, because interfaces can only inherit other interfaces.
My proposal is to create a custom ApplicationSettingsBase implementation that is parameterized with an instance of ISettings. That way, whenever you recieve an ISettings from your components, you instantiate a new CustomAppSettings (see below) and associate that with your component.
Since ApplicationSettingsBase uses a string-to-object key value pair mapping, I propose an interface that does the same.
public interface ISettings
{
Dictionary<string,object> Values{ get; set; }
public object GetDefaultValue(string key);
// Whatever else you might need
}
public class CustomAppSettings : ApplicationSettingsBase
{
public ISettings Settings { get; set; }
public override object this[string propertyName]
{
get
{
return this.Settings.Values[propertyName];
}
set
{
this.Settings.Values[propertyName] = value;
}
}
// There will be more implementation work for this class I'm sure
}
In addition you would need a serialization mechanism for your ISetting instances.
Edit: Fixed some code syntax errors
Lets say that one has a class like Person that has associated with it some default settings implemented in a Setting class. Those settings might be things like "Default Title" or "First Name Required". Correspondingly, other classes like an Address class might also have some default settings. The Setting class persists each setting into a persistent store.
Should one implement a static method in each class like "SetDefaults()" that contains these settings so that an external method can call SetDefaults() on each object type? e.g. Person.SetDefaults() and then Address.SetDefaults()?
Or is there some better object oriented way of doing this?
[Update: this can't be in the constructor because SetDefaults() should be called from an external class at a particular point in time, rather than each time the object is constructed.]
I can't think of many occasions where defaults are truly spanning... given all the different use-cases that an object may go through (not least, things like deserialization - which could end up setting the defaults even though that isn't what was intended).
One option here is IoC; IoC containers like StructureMap have the ability to set properties after initialization, and that is then abstracted from the calling code.
Another option might be some kind of template instance (static), that instances can copy values from. But I think this is risky in a few scenarios. You also get problems if different threads (perhaps requests on a web-server) need different defaults. [ThreadStatic] isn't a good option (although it is an option).
Another option (that provides the greatest flexibility) would be to provide a user-settable factory... perhaps via a delegate or event mechanism - but I struggle to see why you might want this scenario. It isn't one I've seen very often...
re update: if it is only used by the external class; could it perhaps use something like an extension method (rather than the Person class having to know anything about this):
public static class PersonExt {
public static void SetDefaults(this Person person) {
// your code
}
}
Since it sounds like the original Person class doesn't care about SetDefaults, this divorces the logic from Person neatly.
Why not set these defaults when you create the object (in the constructor).
A default is -imho- a value that should be assigned to a property when no specific value is given to that property, so, I think it is a good idea to set those default-values when the object is created (in the constructor, or via a factory).
Or, am i missing something ?
I'd put them in the constructor.
class Person
{
public Person()
{
this.Settings = MakeDefault();
}
public Person(Settings settings)
{
this.Settings = settings;
}
}
You could create a settings class that encapsulate settings for all classes (Person, Address).
You could set default settings for say Person:
// Injected
Settings settings;
Setting personSetting = new ...;
...
settings.StoreSettingsFor(typeof(Person), personSettings);
You could also use a singleton to store this data if you wished, especially if the values are retrieved from storage somewhere as this would cut down on the number of times that the storage is accessed.
(In this instance storage can be datafile, registry, database.)
You can also implement Abstract factory pattern and configure factories with your settings. Or you can alternatively use IoC for injecting dependency into this factory classes.
Simple Factory class for Preson can look following:
public class PersonFactory
{
private readonly ISettings settings;
public PersonFactory(ISettings settings)
{
this.settings = settings;
}
public Person Create()
{
Person p = new Person();
// ... you code for populating person's attributes form settings.
return p;
}
}
In wanting to get some hands-on experience of good OO design I've decided to try to apply separation of concerns on a legacy app.
I decided that I wasn't comfortable with these calls being scattered all over the code base.
ConfigurationManager.AppSettings["key"]
While I've already tackled this before by writing a helper class to encapsulate those calls into static methods I thought it could be an opportunity to go a bit further.
I realise that ultimately I should be aiming to use dependency injection and always be 'coding to interfaces'. But I don't want to take what seems like too big a step. In the meantime I'd like to take smaller steps towards that ultimate goal.
Can anyone enumerate the steps they would recommend?
Here are some that come to mind:
Have client code depend on an interface not a concrete implementation
Manually inject dependencies into an
interface via constructor or property?
Before going to the effort of
choosing and applying an IoC
container how do I keep the code
running?
In order to fulfil a dependency the default
constructor of any class that needs a
configuration value could use a Factory
(with a static CreateObject() method)?
Surely I'll still have a concrete dependency on the Factory?...
I've dipped into Michael Feathers' book so I know that I need to introduce seams but I'm struggling to know when I've introduced enough or too many!
Update
Imagine that Client calls methods on WidgetLoader passing it the required dependencies (such as an IConfigReader)
WidgetLoader reads config to find out what Widgets to load and asks WidgetFactory to create each in turn
WidgetFactory reads config to know what state to put the Widgets into by default
WidgetFactory delegates to WidgetRepository to do the data access, which reads config to decide what diagnostics it should log
In each case above should the IConfigReader be passed like a hot potato between each member in the call chain?
Is a Factory the answer?
To clarify following some comments:
My primary aim is to gradually migrate some app settings out of the config file and into some other form of persistence. While I realise that with an injected dependency I can Extract and Override to get some unit testing goodness, my primary concern is not testing so much as to encapsulate enough to begin being ignorant of where the settings actually get persisted.
When refactoring a legacy code-base you want to iteratively make small changes over time. Here is one approach:
Create a new static class (i.e. MyConfigManager) with a method to get the app setting (i.e. GetAppSettingString( string key )
Do a global search and replace of "ConfigurationManager.AppSettings["key"] and replace instances with "MyConfigManager.GetAppSettingsString("key")"
Test and check-in
Now your dependency on the ConfigurationManager is in one place. You can store your settings in a database or wherever, without having to change tons of code. Down side is that you still have a static dependency.
Next step would be to change MyConfigManager into a regular instance class and inject it into classes where it is used. Best approach here is to do it incrementally.
Create an instance class (and an interface) alongside the static class.
Now that you have both, you can refactor the using classes slowly until they are all using the instance class. Inject the instance into the constructor (using the interface). Don't try for the big bang check-in if there are lots of usages. Just do it slowly and carefully over time.
Then just delete the static class.
Usually its very difficult to clean a legacy application is small steps, because they are not designed to be changed in this way. If the code is completely intermingled and you have no SoC it is difficult to change on thing without being forced to change everything else... Also it is often very hard to unit test anything.
But in general you have to:
1) Find the simplest (smallest) class not refactored yet
2) Write unit tests for this class so that you have confidence that your refactoring didn't break anything
3) Do the smallest possible change (this depends on the project and your common sense)
4) Make sure all the tests pass
5) Commit and goto 1
I would like to recommend "Refactoring" by Martin Fowler to give you more ideas: http://www.amazon.com/exec/obidos/ASIN/0201485672
For your example, the first thing I'd do is to create an interface exposing the functionality you need to read config e.g.
public interface IConfigReader
{
string GetAppSetting(string key);
...
}
and then create an implementation which delegates to the static ConfigurationManager class:
public class StaticConfigReader : IConfigReader
{
public string Get(string key)
{
return ConfigurationManager.AppSetting[key];
}
}
Then for a particular class with a dependency on the configuration you can create a seam which initially just returns an instance of the static config reader:
public class ClassRequiringConfig
{
public void MethodUsingConfig()
{
string setting = this.GetConfigReader().GetAppSetting("key");
}
protected virtual IConfigReader GetConfigReader()
{
return new StaticConfigReader();
}
}
And replace all references to ConfigManager with usages of your interface. Then for testing purposes you can subclass this class and override the GetConfigReader method to inject fakes so you don't need any actual config file:
public class TestClassRequiringConfig : ClassRequiringConfig
{
public IConfigReader ConfigReader { get; set; }
protected override IConfigReader GetConfigReader()
{
return this.ConfigReader;
}
}
[Test]
public void TestMethodUsingConfig()
{
ClassRequiringConfig sut = new TestClassRequiringConfig { ConfigReader = fakeConfigReader };
sut.MethodUsingConfig();
//Assertions
}
Then eventually you will be able to replace this with property/constructor injection when you add an IoC container.
EDIT:
If you're not happy with injecting instances into individual classes like this (which would be quite tedious if many classes depend on configuration) then you could create a static configuration class, and then allow temporary changes to the config reader for testing:
public static class Configuration
{
private static Func<IConfigReader> _configReaderFunc = () => new StaticConfigReader;
public static Func<IConfigReader> GetConfiguration
{
get { return _configReaderFunc; }
}
public static IDisposable CreateConfigScope(IConfigReader reader)
{
return new ConfigReaderScope(() => reader);
}
private class ConfigReaderScope : IDisposable
{
private readonly Func<IConfigReader> _oldReaderFunc;
public ConfigReaderScope(Func<IConfigReader> newReaderFunc)
{
this._oldReaderFunc = _configReaderFunc;
_configReaderFunc = newReaderFunc;
}
public void Dispose()
{
_configReaderFunc = this._oldReaderFunc;
}
}
}
Then your classes just access the config through the static class:
public void MethodUsingConfig()
{
string value = Configuration.GetConfigReader().GetAppSetting("key");
}
and your tests can use a fake through a temporary scope:
[Test]
public void TestMethodUsingConfig()
{
using(var scope = Configuration.CreateConfigScope(fakeReader))
{
new ClassUsingConfig().MethodUsingConfig();
//Assertions
}
}