8

Environment: Visual Studio 2012, .NET 4 Framework, ASP.NET web application (C#)

I'd like to know the best, most advisable approach to accomplish limiting incoming arguments (of any type...int, string, etc...) to a predefined set of desired values. I'd like to know the industry-accepted best way.

(the following code does not work - it's just to better illustrate the question)
Lets say I have a utilities class something like this:

public class Utilities
{
    public string ConvertFromBytes(int intNumBytes, string strOutputUnit)
    {
        //determine the desired output
        switch(strOutputUnit.ToUpper())
        {
            case "KB":
                //Kilobytes - do something
                break;
            case "MB":
                //Megabytes - do something
                break;
            case "GB":
                //Gigabytes - do something
                break;
        }
        //Finish converting and return file size string in desired format...
    }
}

Then, in one of my pages, I have something like this:

Utilities ut = new Utilities();
strConvertedFilesize = ut.ConvertFromBytes(1024,

What I'd like to know is, in the line of code immediately above, what is the best way for me to make it such that "KB", "MB", or "GB" are the only possible string values that can be entered for the "strOutputUnit" parameter? (And) Preferably with intellisense showing the possible available options?


Update: JaredPar I'm using your suggestion and came up with the following reworked code:

public class Utilities
{
        public enum OutputUnit { 
                          KB,
                          MB,
                          GB
                        }

        public string ConvertFromBytes(int intNumBytes, OutputUnit ou)
        {
            //determine the desired output
            switch (ou)
            {
                case OutputUnit.KB:
                    //Kilobytes - do something
                    break;
                case OutputUnit.MB:
                    //Megabytes - do something
                    break;
                case OutputUnit.GB:
                    //Gigabytes - do something
                    break;
                default:
                    //do something crazy
                    break;
            }
            //Finish converting and return file size string in desired format...
            return "";
        }
}

and to call it:

Utilities ut = new Utilities();
string strConvertedFilesize = ut.ConvertFromBytes(1024, Utilities.OutputUnit.MB);

Is this above approach the most efficient way of using the enums as arguments? In the line directly above, having to type in the "Utilities.OutputUnit." part in my method call feels a little clunky...of course I could always assign shorter names, but are there any ways to better streamline the above?

BTW Thanks everyone for the answers. JaredPar i will choose yours since it's correct and came in first. The other answers were very informative and helpful however - thanks to all.

user3070890
  • 83
  • 1
  • 4

5 Answers5

11

In this case instead of using a String you should use an enum.

enum OutputUnit { 
  KB,
  MB,
  GB
}

This will make the choice of input arguments much more explicit for developers. Of course it is not a fool proof operation because a developer can always create an invalid enum value by directly casting from int

OutputUnit u = (OutputUnit)10000;
JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
4

In addition to using an enum in your specific case, from a more general perspectice, you might take a look at (by no means inclusive -- there's more than one way to do it) these:

Here's an article by Jon Skeet on code contracts: http://www.infoq.com/articles/code-contracts-csharp.

The ur-text for design-by-contract — and arguably the best overall book on O-O design — is Bertrand Meyer's Object-Oriented Software Construction, 2nd ed.. The Eiffel language has design-by-contract at its core: Eiffel/Eiffel Studio is a full-fledged Eiffel IDE that produces CLR-compliant assemblies.

Community
  • 1
  • 1
Nicholas Carey
  • 71,308
  • 16
  • 93
  • 135
2

This is exactly what enums are for:

public enum SizeUnit { KB, MB, GB }
SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
1

Enums, as suggested by several others, are by far the most common and recognized way to accomplish this.

There is one other method you can look at that is less common, but quite powerful:

Code Contracts

Code Contracts provide a structure similar to many unit tests. Where they excel is that they also have some IDE support within Visual Studio, to help someone calling your method know what the expected values(contracts) are. Code Contracts are useful when the potential range of allowed values is very large, such that an enum would be cumbersome. The downside is that Code Contracts are not yet universally supported or recognized.

Joel Coehoorn
  • 399,467
  • 113
  • 570
  • 794
0

I am going to suggest you don't use an enumeration, mostly because your switch statement has a section to "do something," which makes it seems like you might want polymorphism. It might be overkill, but you should consider the tradeoffs, at least.

You'll find lots of examples of enumeration classes in the .Net framework. The example I'd give is the Unit type (which is technically a struct, but still works for the point). It uses static members to enumerate {Point, Pixel, Percentage}. It also implements some methods, so you can use polymorphism instead of a switch statement. It also implements a Parse method, which can be used as a factory to get the object you want from a string.

Steve Clanton
  • 4,064
  • 3
  • 32
  • 38