9

In C# what is the best practice for encapsulating variables I need to use in multiple methods? Is it OK to simply declare them at the top of my class above the two methods?

Also if I am using app settings from my config file should I use a getter? like this...

private string mySetting{ get { return WebConfigurationManager.AppSettings["mySetting"]; } }

What best practice is?

4
  • What would be the purpose of a getter, other than adding an additional (and probably unnecessary) layer of indirection? Apr 18, 2013 at 23:41
  • 4
    A getter is much better than multiple calls to WebConfigurationManager.AppSettings because it's much easer to change later Apr 19, 2013 at 1:01
  • @Lavinski: Sure, if you think you might swap out the data store for a different one later. In practice, that seldom happens, and the likelihood that it might happen for AppSettings seems vanishingly small. Apr 19, 2013 at 19:30
  • 10
    A "getter" has the advantage that it makes intellisense work - and you have the key string "mySetting" (which is not checked by the compiler if its written correctly) only in one place.
    – Doc Brown
    Apr 19, 2013 at 20:51

2 Answers 2

5

It's not just OK. According to the book Clean Code it's actually a very good practice, and Uncle Bob really encourages it. A variable used by many methods could show a high degree of cohesion between the methods . Moreover, a high degree of object variables could also hint that said class should be split in two so declaring them as object variables could help you find out hidden class candidates.

Object level variables aren't global variables, so don't be afraid to use them if they should be shared by various methods.

3
  • thanks for your help, though I think when you said cohesion you really meant coupling. Apr 24, 2013 at 19:37
  • No, I meant cohesion. On Software Engineering class also I had a hard time understanding the desire for high cohesion. Usually we lust after low coupling and high cohesion. Coupling is a physical thing that we can see on our own methods. If a class uses another class, then it's coupled to it. If it actually instantiates and object of said class, then it's very couple to it. However, cohesion is more of a logical thing. High cohesion in a class means that its methods belong to a very similar domain, even if they don't share any variable between them.
    – Uri
    Apr 25, 2013 at 2:31
  • Various methods using an object variable don't necessarily mean that they are coupled together. I could have a Encrypter class with a char[] password variable, and have Encrypt(string text); and Decrypt(string text); methods inside it. Both of them use the same password variable, but there's no apparent coupling between them. You may notice, however, that they deal with the same domain, and that is, text encryption. As far as I know, they have a high degree of cohesion, although said class could be split in two. One could argue that encryption doesn't belong to the domain of decryption.
    – Uri
    Apr 25, 2013 at 2:37
4

Encapsulating your settings in a constant manner is a great idea.

What I do is create a settings class either one static global one or multiple instance classes which I'll then manage with dependency injection. Then I load all the settings from configuration into that class on start up.

I've also written a little library that makes use of reflection to make this even easier.

Once my settings are in my config file

<?xml version="1.0" encoding="utf-8" ?>
<configuration>   
    <appSettings>
        <add key="Domain" value="example.com" />
        <add key="PagingSize" value="30" />
        <add key="Invalid.C#.Identifier" value="test" />
    </appSettings>
</configuration>

I make a static or instance class depending on my needs. For simple applications with only a few settings one static class is fine.

private static class Settings
{
    public string Domain { get; set; }

    public int PagingSize { get; set; }

    [Named("Invalid.C#.Identifier")]
    public string ICID { get; set; }

}

Then using my library call either Inflate.Static or Inflate.Instance and the cool thing is I can use any key value source.

using Fire.Configuration;

Inflate.Static( typeof(Settings), x => ConfigurationManager.AppSettings[x] );

All the code for this is in GitHub at https://github.com/Enexure/Enexure.Fire.Configuration

There is even a nuget package:

PM> Install-Package Enexure.Fire.Configuration

Code for reference:

using System;
using System.Linq;
using System.Reflection;
using Fire.Extensions;

namespace Fire.Configuration
{
    public static class Inflate
    {
        public static void Static( Type type, Func<string, string> dictionary )
        {
            Fill( null, type, dictionary );
        }

        public static void Instance( object instance, Func<string, string> dictionary )
        {
            Fill( instance, instance.GetType(), dictionary );
        }


        private static void Fill( object instance, Type type, Func<string, string> dictionary ) 
        {

            PropertyInfo[] properties;
            if (instance == null) {

                // Static
                properties = type.GetProperties( BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly );
            } else {

                // Instance
                properties = type.GetProperties( BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly );
            }

            // Get app settings and convert
            foreach (PropertyInfo property in properties) {
                var attributes = property.GetCustomAttributes( true );
                if (!attributes.Any( x => x is Ignore )) {

                    var named = attributes.FirstOrDefault( x => x is Named ) as Named;

                    var value = dictionary((named != null)? named.Name : property.Name);

                    object result;
                    if (ExtendConversion.ConvertTo(value, property.PropertyType, out result)) {
                        property.SetValue( instance, result, null );
                    }
                }
            }
        }
    }
}

Your Answer

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

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