views:

531

answers:

11

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.

A: 

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!

anthares
What is the benefit of this over using constant values? With a dictionary you get fast lookup, yes, but not as fast as referencing a constant value directly.
Dan Tao
@Dan The benefit is that we reuse the nomenclature in the enum type. We can used everywhere the semantic needs it and this enum type which represents a nomenclature is linked with a user friendly nomenclature in the dictionary.
anthares
@anthares: Sounds like you're talking about having an efficient way to get a string from an enum *that you're actually using as an enum*. I got the impression the OP is more concerned with cases where you just care about a constant string value; but I could be wrong.
Dan Tao
@Dan Yeah you got it right. May be I have misunderstood the question.
anthares
@anthares: Dan is right about this. We're simply interested in fixed plain strings since they are 'forced upon us' otherwise we would have chosen enums in the first place :-)
Rob van Groenewoud
+9  A: 

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.

AakashM
That's probably the reason why the use of a struct made me frown at first, but I didn't think of checking the 'convention'. Thanks for the heads up. This answer is very useful for making the choice between the struct and static class and will probably sufficient to do the job. However I'll have to check whether using resource files might be suitable here.
Rob van Groenewoud
I'm accepting this answer as it seems suitable for this particular situation, since it is extremely unlikely the strings will change. Using the resource files is interesting but adds too much complexity to the current code at the moment.
Rob van Groenewoud
+3  A: 

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.

JaredPar
+9  A: 

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.

Andrew
+1, this is the answer. And not just for internationalization, but also that using a resource files allow you to correct errors or update your strings without re-building the whole app.
Joel Coehoorn
Funny I said the same thing earlier than this answer.. where are my upvotes?? :P
KP
In this case, we're pretty sure the strings will not change, using resource files seems to be a bit of overkill for this particular situation. A static class will do the job (for now). However I'll keep this in mind for future use. Thanks!
Rob van Groenewoud
+6  A: 

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...

KP
Check the timestamps and you were 1 minute later, but I'll give you +1 :)
Andrew
LOL thanks. I upvoted yours earlier...
KP
A: 

tbh i think the strings should be moved out into an APP.CONFIG OR WEB.CONFIG file. you can then write a static class to wrap the calls to the config file.

then if the strings change you don't need to recompile.

static class is far better because then you don't risk having several structs initialised with the same data (the argument for is that you are saving memory when they are unneeded - which is not a great argument as strings are not large).

I wouldn't involve a struct anywhere.

John Nicholas
Too much configuration is worse than too little. KISS principle is a good idea to follow.
Konstantin Spirin
Config files seem to be a bit of overkill for the intented use, since we're not looking for a fully configurable set of strings.
Rob van Groenewoud
see your point .. i tend to use the config files in favour of resource files for things like this. At least then it is all in one place with one access method.
John Nicholas
A: 

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.

BFree
A: 

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.

Max Toro
+3  A: 

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.

stack
+1  A: 

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.

Jesse C. Slicer
Good point. I remember having read that earlier, but didn't put it in practice for a long time, since most of my code doesn't seem suitable for structs :-)
Rob van Groenewoud
+1  A: 

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";
}
Konstantin Spirin
Care to explain why you use 'static readonly' instead of const?Const would be evaluated compile-time, which is fine for the intended use.
Rob van Groenewoud
I've listed const drawbacks: simple types only and compiled-in values. Use const if you are 100% sure it won't change (like Math.Pi, for example)
Konstantin Spirin
I get your point, thanks for elaborating. I don't expect the values to change, but you never know who decides to change the values in his endless wisdom ;-)
Rob van Groenewoud