views:

197

answers:

9

In almost every project, I can't decide on how to deal with certain global constant values. In the older days, when I wrote C++ programs which didn't used dll's, it was easy. Just create and .h file with a number of const that described certain constant values for my project. Then I had every file include it, and ta-da! It worked. Clean, respected the DRY principle and was simple.

Now my projects are C# .Net, which gives me a large range of options to deal with this problem. From what I know:

  1. Create an Assembly whose only purpose is to hold constant values for my project. Every other Assembly should then reference this one. I respect DRY and KISS, since adding references is simple enough. Main problem here is that I'd need to recompile the whole source to update those values.

  2. Use a app.config file and have all other Assemblies retrieve the constant during initialization. So I add the overhead of having to initialize everything just to access a global value. Is more flexible but also more painful.

  3. Use resources. I think it's the same as with app.config.

So, I know there's a better way to do this constants declaration. But I don't know and, so far, have been unable to find how to do it. Can you please help? I have candy!

Thanks all

+1  A: 

For C# projects, if you want constants, arguably the best thing to do is use the Settings file provided in Visual Studio under your project settings. It supports custom types, and AFAIK anything that is marked as serializable.

As many developers have told me, don't reinvent the wheel. There are two setting types, user-settings and application-settings, the main difference being that application-settings are read-only at run-time. That's essentially what you want, it sounds like.

Stefan Valianu
That's very near what I want. I already imagined that Settings are that I wanted, but I don't know to use Settings when the value is to be used across multiple assemblies. Do you have an idea?
Bruno Brant
You can add the app.config of one assembly as a link in the other assembly. Project -> add existing reference -> there's a drop down that allows you to add as a link, which won't make a local copy. It's not perfect, but it works!
Stefan Valianu
+3  A: 

You could use the readonly keyword instead of const to avoid having to recompile everything when the values change.

Excerpt from MSDN:

While a const field is a compile-time constant, the readonly field can be used for runtime constants

See this link for more details.

bde
+1 because I didn't knew about that difference in behavior. Still, are you proposing the creation of an extra Assembly to hold the constants?
Bruno Brant
It depends on what exactly your constants are. Some of the other answers have good points about trying to minimize the scope of constants and grouping them with the code that uses them. However, I could see that in some situations creating an extra assembly would be helpful. At any rate, even if you don't create a new assembly you can use `readonly` on the constants in the assemblies you have to avoid recompiling the whole system.
bde
+4  A: 

Er, assuming that your constants aren't enormous, you should just be able to declare them as public const in a class of your choice:

namespace MyProject
{
    public class Awesome
    {
        public const int SomewhatAwesome = 1;
        public const int ExtraAwesome = 2;
        /* etc */
    }
}

You should include your const members in the classes that they relate to, i.e. if SomewhatAwesome and ExtraAwesome are used for and by the Awesome class, then they should be constants declared in that class. Don't create an extra assembly just to hold constant values, and don't create a dedicated static class or namespace for your constants unless there really is nothing else that groups the constants together.

The app.config file is for settings that can be changed by the end user at runtime. Don't put constants that shouldn't change in that file. Resources are for "big" objects, such as text files and images, that would be tedious or impossible to include as literal class members. Don't put simple things like integers and short strings in resources.

JSBangs
The constants I am talking about will be used by many objects along the solution. Still holds?
Bruno Brant
@Bruno, yes, you just have to find the place that's logical to put them. Generally constants should be members of `Foo` if you mostly pass them *to* `Foo` as parameters, if they come *from* `Foo` as return values, or if they otherwise *describe* `Foo`.
JSBangs
+1  A: 

Looks like using a class is Microsoft's recommendation. http://msdn.microsoft.com/en-us/library/bb397677.aspx

Josh
+1 because of the link. However, it doesn't affirm that I should use a class instead of the Settings class/namespace.
Bruno Brant
A: 

If you want the values to be capable of being changed at runtime, use app.config.

If you want them to be fixed at runtime then you're going to have to (and want to, to stop users messing around with them) recompile every time you want to change them, so use whatever's appropriate for your language. In the case of C#, some kind of GlobalValues class/assembly.

Don't use a resource file for global values or settings unless you want to swap sets of values in and out as a group (e.g. when compiling for a different language).

gkrogers
Can you elaborate a bit more?
Bruno Brant
I accepted your answer because of the third paragraph. You're right, that's is the purpose of the Settings file, to have different groups of settings (and to save user settings). So I will stick with classes after all.
Bruno Brant
A: 

I think the main disconnect here is trying to force a C way of thinking into a C# project. If you have a bunch of constants that you just want to throw in a file together, I would take that as a sign that you need to re-think your design. Spend some time to think about which class the each constant really should belong to and put it there.

That being said, I really don't think you should treat these constants differently from other data, they should live in a dll. This also has the added benefit of being able to version the dll should the 'constants' change.

Dolphin
One thing though: I always though that dlls are essentially for code, not data. That's where these questions are coming from.
Bruno Brant
A: 

I have a few projects that I've been working on at work and we decided to create a static class for our global values and functions:

namespace MyNamespace
{
    public static class MyGlobalClass
    {
        //Global stuff here
    }
}

That way all global items are always visible and you don't have to instantiate the class to use them.

Mike Webb
A: 

compile time constants vary with the universe in which you inhabit. So pi and e are compile time constants.

runtime constants could potentially vary with each new version.

settings could potentially vary each new time an application is run (or more often depending on how settings are implemented, i.e. db drive, config file driven, etc).

MatthewMartin
A: 

Try to avoid the God class and static 'helper' classes if you can help it. You should try your best to move the constant data into the appropriate classes.

I'm assuming that since you are using C# you want to develop with proper object oriented designs, principles, and patterns. Remember, objects are about behavior --not necessarily functionality. In my opinion, thinking functionally leads to producing procedural code.

You can use the Singleton pattern when the data is used throughout many objects. Although, it's not necessarily a best practice. Lately, I've started using IoC dependency injection more in these situations with Unity and MEF.

Jerod Houghtelling