1

I've been trying to mull over a question I am not sure how to solve and it probably has a simple solution however I am trying to work out a simple solution.

The following scenario is as such. Let's say we have the following variables.

string username;
string password;
string domain;
string location;

and I want to run the same function across them

void AssignValueFromConfigFile() 
{
    username = ConfigurationManager.AppSettings["username"];
    if (username == null)
        throw new ValueNotFound("username");

    password = ConfigurationManager.AppSettings["password"];
}

..... etc for each one

This is obviously really tedious and the wrong way to do this. We can make this work in a dictionary if we had:

var values = new Dictionary<string,string>() { {"username",""},{"password",""},{"domain",""},{"location",""}}

void AssignValueFromConfigFile()
{
    foreach(var val in values) 
    {
        val.Value = ConfigurationManager.AppSettings[val.Key];
        if (val.Value == null)
            throw new ValueNotFound(val.Value);
    }
}

But then we lose the ability to call the local variables and have to know what they are in the dictionary. How is this achieved?

5
  • Where's the value to putting a method that takes a string key around the ConfigurationManager dictionary that... takes a string key?? As far as I see, you can completely ditch this code and just access the config. Side note: That class was superseded a decade ago. You should be using the strongly typed application settings.
    – RubberDuck
    Dec 7, 2016 at 0:36
  • @RubberDuck can you provide example of strongly typed app settings? apparently i've been doing it wrong - thanks!
    – solidau
    Dec 7, 2016 at 20:45
  • 1
    @SeanReeves the links at this page should help you out. msdn.microsoft.com/en-us/library/bb397750(v=vs.110).aspx
    – RubberDuck
    Dec 7, 2016 at 20:51
  • @RubberDuck Fantastic! I will be moving to that method. Thanks!
    – solidau
    Dec 7, 2016 at 20:57
  • @RubberDuck I'm not sure I interpreted your question correctly? I was using this as a trivial example that adds extra error handling. I wasn't aware of strongly typed settings, thanks for pointing that out :). Also I understand both these answers are horribly wrong. I was more or less trying to ask for an alternative without giving the example below and the response being, just do that. It might not have prompted the reflective response which was essentially what I was after without the overhead.
    – Dan W
    Dec 7, 2016 at 23:10

2 Answers 2

4

There's no need for a dictionary (unless you want one, of course). You could assign each variable by reference, e.g.

void AssignValueFromConfigFile(string name, ref string value) {
    value = ConfigurationManager.AppSettings[name];
    if(value == null) {
        throw new ValueNotFound(name);
    }
}

    string username;
    string password;
    string domain;
    string location;
    AssignValueFromConfigFile("username", ref username);
    AssignValueFromConfigFile("password", ref password);
    AssignValueFromConfigFile("domain", ref domain);
    AssignValueFromConfigFile("location", ref location);

However, a much neater solution would be to apply the command/query separation pattern, e.g.

string GetValueFromConfigFile(string name) {
    var value = ConfigurationManager.AppSettings[name];
    if(value == null) {
        throw new ValueNotFound(name);
    }
    return value;
}

    var username = GetValueFromConfigFile("username");
    var password = GetValueFromConfigFile("password");
    var domain = GetValueFromConfigFile("domain");
    var location = GetValueFromConfigFile("location");

You have one function that reads the data and guarantees that it is not null. The calling code then decides what to do with the data.

7
  • 2
    Unnecessary use of ref: -1. "However, a much neater solution..." +1. Claim calling a function to set a variable is "command/query separation pattern": -1. Sensible code suggestion: +1. Overall: 0. :/
    – David Arno
    Dec 6, 2016 at 14:14
  • +1 for the second example code... As a Java dev, the first one unsettles me, and also makes unnecessary use of language features with no real gain. Dec 6, 2016 at 22:18
  • I have accepted this as the solution but my problem with it is the scenario of 100 local variables. I can assume at that point you are doing something wrong but the scenario exists. If that is a circumstance @Sean Reeves solution will cater well, alternatively add in a custom attribute referencing the stored name. I don't understand why people are downvoting, I appreciate the time spent on the answers to what I thought was a rather simplistic question.
    – Dan W
    Dec 7, 2016 at 5:02
  • @DanW If you have 100 local variables, the first step towards a solution is probably to find a good way to consolidate those values into fewer variables. Dec 7, 2016 at 5:51
  • @DavidArno: I'm a big fan of CQS and I tend to think in terms of it. Yes, this is an extremely trivial use of CQS, but I believe it's still valid. How else would you describe the act of separating the calculation of an rvalue and the assignment to an lvalue? Dec 7, 2016 at 11:54
1

You might be able to get cheeky with reflection if you want to do this to all properties of a class, for example:

public class LoginViewModel 
{
    string username;
    string password;
    string domain;
    string location;

    public void init()
    {
        var props = this.GetType().GetProperties();
        foreach(var prop in props) 
        {
            prop.SetValue(this, ConfigurationManager.AppSettings[prop.Name]);
            if (prop.GetValue(this) == null)
                throw new ValueNotFound(prop.Name);
        }
    }
}
2
  • This is essentially what I was after without the overhead of reflection. I think I am just define envisaging a pipe dream. What I have is exactly the same as @Christian Hayter just wanted to know if there was a quicker way and you proved this. Thanks!
    – Dan W
    Dec 6, 2016 at 22:08
  • jw why people are downvoting.... please leave coment
    – solidau
    Dec 7, 2016 at 1:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.