views:

226

answers:

7

For example:

(1).SomeFunction().Equals("one")
(2).SomeFunction().Equals("two")

I really only need it for digits 1-9 in the case I'm working with, should I just use a switch/select case?

Update I won't need localization in this case either.

Update 2 Here's what I ended up using:

Private Enum EnglishDigit As Integer
    zero
    one
    two
    three
    four
    five
    six
    seven
    eight
    nine
End Enum

(CType(someIntThatIsLessThanTen, EnglishDigit)).ToString()
+11  A: 

How about an enumeration?

enum Number
{
    One = 1, // default value for first enum element is 0, so we set = 1 here
    Two,
    Three,
    Four,
    Five,
    Six,
    Seven,
    Eight,
    Nine,
}

Then you can type things like...

((Number)1).ToString()

If you need localization then you can add a DescriptionAttribute to each enum value. The attribute's Description property would store the name of the resourse item's key.

enum Number
{
    [Description("NumberName_1")]
    One = 1, // default value for first enum element is 0, so we set = 1 here 

    [Description("NumberName_2")]
    Two,

    // and so on...
}

The following function will grab the value of the Description property from the attribute

public static string GetDescription(object value)
{
    DescriptionAttribute[] attributes = null;
    System.Reflection.FieldInfo fi = value.GetType().GetField(value.ToString());
    if (fi != null)
    {
        attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);
    }

    string description = null;
    if ((attributes != null) && (attributes.Length > 0))
    {
        description = attributes[0].Description;
    }

    return description;
}

This can be called in the following manner:

GetDescription(((Number)1))

From that you can then pull the relevant value from the resource file, or just call .ToString() if null was returned.

Edit

Various commenters have pointed out (and I have to agree) that it would be simpler to just use the enum value names to reference localised strings.

Richard Ev
Enumeration is an easy solution, unless of course you need localization :)
OregonGhost
I won't need localization in this case either, but good point!
travis
I updated my answer to include a solution that can be localized.
Richard Ev
As I suggest in my answer, I'd rather use the enumeration name and enumeration value name as the key for resource strings. Seems easier than yet another attribute that has to be understood when reading the code. But it would work as you suggest, I guess. By the way, I'd suggest adding `Zero` to your enumeration even if not needed by travis, since `0` is a valid value for any enum, even if not explicitly defined :)
OregonGhost
Now that you added the code on how to get the description... While I think that this is an interesting solution (and may be of use for other problems), it's in my opinion just so much unnecessary code just to get the resource identifier, when the enumeration name and enumeration value name are already a fine resource identifier, loadable with a one-liner :)
OregonGhost
@OregonGhost I have to agree with you there. I've added a comment to my answer, but will leave the approach there as otherwise the comments you added won't make sense. :-)
Richard Ev
that's true, but again as I've said before, in this case, I will never, ever need anything other than English :-)
travis
@travis: It's fine for you, but since this answer will remain on the Internet for a very long time, others may find the additions useful, so it just improves the answer, even if it's more than you'll ever need :) By the way, many people thought they'll never need anything other than English (or more than 640K, for that matter) :D I'd give this answer an upvote, if I hadn't done that already :)
OregonGhost
+4  A: 

create a dictionary of strings:

string[] digits = new string[] 
{
   "zero",
   "one",
   "two",
   ...
};

string word = digits[digit];
Andrey
+1  A: 

Use a lookup table; an array will do. It's no slower than an enum, and it's easier to localize.

edit

Andrey's code sample is what I was suggesting, although I think calling it a dictionary is a bit confusing.

Steven Sudit
I won't need localization in this case, thanks!
travis
I would love to hear some explanation for the downvote, unless it's just strategic gaming.
Steven Sudit
A: 

I don't think there are any built-in functions to do this. I would use select case.

xpda
Why select/case instead of lookup?
Steven Sudit
A lookup table should work just as well.
xpda
+1  A: 

If you don't need localization, I'd suggest Richard Ev's solution. For localization, however, I'd suggest adding the ten digit names to a resource file, for example NumberName_0 to NumberName_9. This way, when looking up a number, you can just load the resource with the name String.Format("NumberName_{0}", mydigit).

The same technique, by the way, also works fine for localizable enumeration names or descriptions.

OregonGhost
Resource tables make sense to me, but I would load all ten values into an array at startup.
Steven Sudit
We could take OregonGhost's resource strings and load them into Andrey's array, and then I think we'd have something.
Jeffrey L Whitledge
@Jeffrey L Whitledge: Of course you can load them into an array, but you have to do that every time the user changes the culture (if your app supports on the fly switching). That's one more thing that may be forgotten, so I wouldn't bother if loading the resource strings every time doesn't introduce a performance issue :)
OregonGhost
@OregonGhost - True. The app should also check to see whether the user is running on a flash drive or magnetic disk before deciding between lazy and eager resource loading. ;)
Jeffrey L Whitledge
@Jeffrey L Whitledge: Actually, no. That would be premature optimization, just like loading the values into an array ;) Don't think I don't get your joke, but to clarify, I suggest the exact opposite: Be lazy until it is proven to be a bottleneck. Saves so much time. The difference is this: You have to: 1. create the array, 2. fill the array by loading the strings (whenever culture changes), 3. access the array to get the string. I have to: 1. load the string. Done. If you prove with a profiler that this string loading takes too much time (for the app), I agree with an array. That's my point:)
OregonGhost
A: 

If you are using 2008:

public static String AsWord(this int aNumber) {
    return ((Number) aNumber).ToString();
}

enum Number {
    One = 1,
    Two,
    Three,
    Four,
    Five,
    Six,
    Seven,
    Eight,
    Nine,
}
Hupperware
+1  A: 

Why stop at 1-9...

C#'s version of the way Squeak Smalltalk does it for all numbers to a vigintillion:

    public static String AsWords(this int aNumber) {
        var answer = "";
        if (aNumber == 0) return "zero";
        if (aNumber < 0) {
            answer = "negative";
            aNumber = Math.Abs(aNumber);
        }

        var thousands = new[] {"", "thousand", "million", "billion", "trillion", "quadrillion", "quintillion", "sextillion", "septillion","octillion", "nonillion", "decillion", "undecillion", "duodecillion", "tredecillion", "quattuordecillion", "quindecillion", "sexdecillion", "septendecillion", "octodecillion", "novemdecillion", "vigintillion"};
        var thousandCount = 0;
        while (aNumber > 0) {
            var underOneThousandName = ThreeDigitName(aNumber % 1000);
            aNumber = aNumber / 1000;
            if(underOneThousandName != "") {
                if (answer != "") answer = "," + answer;
                answer = underOneThousandName + " " + thousands[thousandCount] + answer;
            }
            thousandCount += 1;
        }
        return answer;
    }

    private static string ThreeDigitName(int aNumberLessThanOneThousand) {
        if (aNumberLessThanOneThousand == 0) return "";
        var units = new[] {"one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eightteen", "nineteen"};
        var answer = "";
        if (aNumberLessThanOneThousand > 99) {
            answer = units[(aNumberLessThanOneThousand / 100) - 1] + " hundred";
            if (aNumberLessThanOneThousand % 100 != 0)
                answer += " " + ThreeDigitName(aNumberLessThanOneThousand % 100);
            return answer;
        }
        if (aNumberLessThanOneThousand < 20) return units[aNumberLessThanOneThousand -1];
        var multiplesOfTen = new[] {"twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"};
        answer += multiplesOfTen[(aNumberLessThanOneThousand / 10)-2];
        if (aNumberLessThanOneThousand % 10 != 0) answer += "-" + units[(aNumberLessThanOneThousand % 10)-1];
        return answer;
    }
Hupperware
Ha, that's just a bit overkill for my purposes. :-)
travis
Put it in a library and use it later ;)
Hupperware
+1 for this nice solution, though it's another solution that's not easily localizable: Take, for example, the number 99 in French, which is quatre-vingt-dix-neuf (literally four-twenty-ten-nine), or even the simple 21 in German (einundzwanzig, literally oneandtwenty). Unfortunately, there's no easy solution for this problem :-/
OregonGhost