Question

A co-worker just created the following construction in C# (the example code is simplified). His goal was to shorten the notation for all predefined strings in the rest of the code.

public struct PredefinedStrings
{
    public const string VeryLongName = "Very Long Name";
    public const string AnotherVeryLongName = "Another Very Long Name";
    public const string TheLastVeryLongName = "The Last Very Long Name";
}

public static void MethodThatUsesTheNames()
{
    Console.WriteLine(PredefinedStrings.VeryLongName);
    Console.WriteLine(PredefinedStrings.AnotherVeryLongName);
    Console.WriteLine(PredefinedStrings.TheLastVeryLongName);
}

Although it seems to work fine for him, I can't stop wondering whether he should have used a static class instead of a struct or if there's a more elegant way to achieve this.

What would be the preferred way to do this? Please also explain why.

Was it helpful?

Solution

With the struct solution, there's nothing to stop some other code doing new PredefinedStrings(), which won't do anything bad, but is something it's semantically confusing to allow. With a static class the compiler will forbid creation for you. And it goes without saying that static class is the preferred way of providing constants in the Framework.

edit to add, I said that second part without evidence - I have since searched and reasonably quickly found System.Net.Mime.DispositionTypeNames and System.Net.WebRequestMethods.Http.

OTHER TIPS

I would prefer the strings all being in a resource file and not embedded within the code - primarily for internationalisation reasons. This can then be accessed via a static class with the values as property members.

Besides a static class and struct, why not consider using resource files for constant strings? These can be accessed very easily as SomeNamespace.ResourceName.KeyName, and depending on where they are located in your project can be managed externally without recompiling if need be...

Simple rule of thumb: never use structs until you have no other choice.

Constants have a couple of drawbacks:

  • only simple types can be used (strings, numerics, etc.)
  • constants are injected into referencing assemblies. If you recompile assembly with constants and don't recompile assembly that uses constants, you'll get into trouble

I would write your code like this (notice rename refactoring too):

public static class KnownNames
{
    public static readonly string VeryLong = "Very Long Name";
    public static readonly string AnotherVeryLong = "Another Very Long Name";
    public static readonly string TheLastVeryLong = "The Last Very Long Name";
}

It sounds like you're looking for a resource file (.resx). It's a decent place to store such strings, and abstracting your strings into a .resx will make it easier to localize your application in the future. The MSDN page at http://msdn.microsoft.com/en-us/library/1ztca10y.aspx is a decent start for more information.

There is nothing functionally wrong with this code. But stylistically I agree a static class is better. A static class declares the intent of the type is to only hold static / constant data.

Don't forget the recommendation that a struct size should be about 16 bytes. Given a 32-bit system, that's 4 System.String references right there. I'd say you're better off with a static class if the number of strings will increase.

static class seems to be the best way to go because it's the most standard and expected. I thought the struct/const versions might be faster but after some tests they were not.

Here are the results of my quick test that included length, compare, concat, copy, indexOf, and Substring. It was run under .Net 4.0 in release without a debugger attached.

                                          .Net 3.0  .Net 4.0
static class with static read-only string:  0.217   0.364  seconds
static class with const            string:  0.211   0.361  seconds
struct       with static read-only string:  0.211   0.372  seconds
struct       with const            string:  0.214   0.371  seconds
Properties.Resources               string:  1.173   1.268  seconds

They were all about the same performance except for when using a resource file, which is slower. While Properties.Resources is slower, it is not stored in the executable so that can be more appropriate in some cases. So use either "static class" or Properties.Resources storing strings in my opinion.

Structs are normally avoided unless they meet certain criteria as detailed in this answer.

Since your co-worker is not using it to store a value, he should be using a class, not a struct.

I think static is better and here's my reasoning. If this code lives in some library, and another piece of code consumes this library, if the value of the constant fields change, then not only will this library need to be recompiled (duh) but you'll have to recompile the code consuming this library as well. The reason for that is, the compile inserts the constant values wherever you reference them. If you use static though, you won't have this problem, as you're referencing the field not the value.

In my practice for this purpose we use Dictionary<enumNameType, string>. Where enumNameType is the different type of names you can have (in your case) ... This dictionary is wrapped in a static class and is cached - we create it just the first time we use it and then return the same object ...

I hope this will be useful for you, too!

I use structs for constants too, but only for internal use, not for public APIs. It feels natural since enums are also converted to structs.

The simple fact that you are allowed to create a new object that is intended to be a constant is clear evidence of bad practice (usually). I say "usually" because .NET does utilize the concept occasionally, though it is unclear why.

Of course, you can always do stuff like this:

public class Foo
{
    public struct Bar
    {
        public static double A = 100;

        public Bar(double a)
        {
            A = a;
        }
    }
}

Which does technically justify the creation of Bar; however, there's no guarantee the constant Bar would ever be same (even in a single-threaded environment) and is ultimately of little use.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top