Access nested members in custom Settings-Class

73 Views Asked by At

I thought I had fully understood classes in C#, but atm I'm trying to create a custom Settings-Class for a Project of mine, but I just can't get it right.

What I want to achieve:

  • Have a class which will only exist one time AS SETTINGS for the App.
  • Values inside the settings class shall be grouped by their use in the App.
  • Values can be accessed directly inside the App.
  • Values in the Settings for the Program may differ from those in an object to be written to disk (for example).
  • Being able to save/load it to/from disk.

Is the only way to achieve this to have nested classes within the settings class and create an instance of them?

For context:

At Startup Load() returns a loaded one from disk (if exists) and if not a new one with standard values:

internal static class LoadedData
{
    internal static MQSettings Settings { get; set; } = Tools.Settings.Load();
    ...
    ...
}

I'd like to be able to access the members like so:

string ConfigFolder = LoadedData.Settings.Foldernames.Config;
string UserTable = LoadedData.Settings.Tablenames.User;

There is no need for the nested-class, other than to have them grouped under one name (e.g. Foldernames). I had hoped it would work something like so. Or to have a static nested class or something like that.

internal class MQSettings : BaseClasses.SaveableObject
{
    public override string Filepath => StaticSettings.MQSettingsPath;

    internal List<string> MandatoryFolders { get; set; }
    internal List<string> MandatoryTables { get; set; }    

    internal class Foldernames
    {
        internal string Config { get; set; }
        internal string Backups { get; set; }
        ... more Foldernames
    }

    internal class Tablenames
    {
        internal string Members  { get; set; }
        internal string User { get; set; }
        ... more Tablenames
    }
    ....
}

The only thing I can come up with is this but that feels just wrong somehow.

So, is there any other (or right) way to achieve that the fields inside MQSettings are grouped and accessible via LoadedData.Settings.SomeType.Membername ?

internal class MQSettings : BaseClasses.SaveableObject
{
    public override string Filepath => StaticSettings.MQSettingsPath;

    internal List<string> MandatoryFolders { get; set; }
    internal List<string> MandatoryTables { get; set; }

    internal _Foldernames Foldernames { get; set; }
    internal _Tablenames Tablenames { get; set; }


    internal class _Foldernames
    {
        internal string Config { get; set; }
        internal string Backups { get; set; }
    }

    internal class _Tablenames
    {
        internal string Members { get; set; }
        internal string User { get; set; }
    }
    ....
}

Any help or comments are appreciated.

Edit:

What I forgot to mention is, that nested types also may have nested types.

For example: Columns for a Database-Table. Which are of course table-specific and the name for the table is specified within this settings here.

Do I have to create nested types of nested types of... ? Let's say the ID column of a table ...: LoadedData.Settings.Database.Fieldnames.-sometable-.ID.

That's where I'm loosing it. And what about new tables which are created with this App? Which of course have their own columns, which need to be saved here. Maybe then it's better to have a List of Tables in the Settings?! How do I do that? I think I'm confusing myself.

internal class MQSettings : BaseClasses.SaveableObject
{
    internal _Foldernames Foldernames { get; set; }
    
    internal _Database Database { get; set; }

    internal class _Foldernames
    {
        internal string Config { get; set; }
        internal string Templates { get; set; }
        internal string Backups { get; set; }
    }
    

    internal class _Database
    {
        internal AppName.DataTypes.Database.Credentials? Credentials { get; set; }

        internal _Fieldnames Fieldnames { get; set; }           

        internal class _Fieldnames
        {
            internal _Table Table { get; set; }                 
                
            internal class _Table
            {
                internal string ID { get; set; }
            }        
        }              
    }
}

How do I access that stuff? I hope I could make myself clear.

1

There are 1 best solutions below

0
On BEST ANSWER

Some languages like TypeScript would allow you to define a single type with nested declarations concisely and all in one place. C# isn't like that. You have to declare each type, and then separately declare a property of that type, even if you only ever plan to use that type for that one property.

I would recommend embracing the standard patterns used in this language and framework. I personally wouldn't even bother declaring the classes as nested classes: just give them descriptive enough names to avoid naming collisions within their namespace.

For things that are truly just one-time app configuration, look into the standard Configuration paradigms provided in .NET. They are probably the "right" way to load configuration into your app. Trying to use a static property that loads itself on initialization will make your code difficult to unit test, and will likely lead to other problems caused by tight coupling.

You mention storing multiple table names and their field names in this configuration. If your code is tightly coupled to the concepts embodied by those field names, there's probably something wrong with this design. Are you trying to plan for an eventual future where those field names change? If you use an ORM like Entity Framework, that sort of change should only require changing one line of code. What reasons do you have for wanting to change those field names per environment? You may need to re-think how your systems are coupled.

On the other hand, maybe those tables and fields are purely dynamic. I've written software designed to help users build queries against any database schema they configure.

If your configuration is getting very advanced/heavy, you may want to carefully examine whether this is the right way to load and store it. Usually true app configuration is reserved for things like connection strings. It may be more appropriate to store more complex data in a database and load it via something like Entity Framework.