views:

283

answers:

4

Using VS2010 and .net V4.0 I would like to achieve the following:

I already have 2 resource files in my project for 2 languages - English and Czech.

I must say Resource Management in .net is excellent, I am suprised even to get code completion when implementing a String for example:

string desc = Strings.ResourceManagerDesc

This gets the string associated with the current culture of the thread.

Now I am trying to create an Enum that can have the String portion of the Enum interpreted from the Strings resources. In the following way (This code DOES NOT WORK):

public enum DownloadStatus
{
 1 = Strings.DownloadState_Complete,
 2 = Strings.DownloadState_Failed,
 3 = Strings.DownloadState_InProgress
}

This is a made up example, but you can see the point here. Since the above code won't work, is there a best practice way to achieve what I want?

+1  A: 

Enums are compiled up as part of the assembly. You're essentially assigning a method to the value of the enum isn't of a constant value - the CLR is not smart enough to work out the value at compile time, it needs to be a constant.

I'd suggest that you create a different enum for each language (forget resources) and use a helper class to return the correct one depending on the langauge-context needed.

David Neale
Anyway to have a static resource?
JL
@David, I think this is the crux of the matter, no dynamic assignment, no matter what (resource or any other dynamic field). So I guess Enum is the wrong tool for the job in this case.
JL
But this would still be runtime behaviour - not compile time for the enum.
Adam
+1  A: 

Hi,

Enums cannot inherit from strings. In code you do not need to be concerned with the language of the code, so your enum can simply contain the relevant states.

Looks like what you need is a utility method to convert the enum value to the relevant string representation - simply make a method for this.

EDIT: when you use an enum to switch on cases, but need further information per enumerated value, I tend to drop the enum and create a host of static references and use those in the check instead. This reference can be a class wrapping an enum value, which could then expose helpful titles or descriptions.

Adam
Enums cannot inherit from anything. They all inherit from System.Enum. In any case, in the above example the OP is basing his enum on the default of int. The problem is that he is trying to dynamically assign the enum's value.
David Neale
I'll keep the question open for now, I had through of your suggestion, but it could be possible there is a more cleaner solution, thanks Adam.
JL
Sorry, I suppose they cannot inherit. But they can specify a type:public enum MyShorts : short{ }
Adam
Yes, although it looks a little like inheritance it is actually just changing the underlying representation.
David Neale
Hi JL. A "cleaner" solution would be to make this utility method an extension method on your enum, I just tried this and it works fine. It would be the same solution, but the utility method would be housed on the type itself.HTH.
Adam
+1  A: 

You can get a resource via a string, and since you can convert an enum to a string, this is quite straightforward.

enum Whatever { Ready, Set, Go }

public static string GetEnumerationString(Enum enumeration)
{
    string resourceName = 
        string.Concat(enumeration.GetType().Name, "_", enumeration);
    return ResourceManager.GetString(resourceName);
}

Now in this implementation we prefixing all enum resources with the name of the enum. In a project we did it just prevents collisions with other resources and makes them easy to find. You'd have to then ensure adding resources called Whatever_Ready, Whatever_Set and Whatever_Go.

Similarly, if you were to look at the generated code for the static member Strings as you originally wrote you'd probably see:

public static string DownloadStatus_Complete
{
    return ResourceManager.GetString("DownloadStatus_Complete", Resource.Culture);
}
Robert Paulson
A: 

IMO, the Enum value should be reflected to the domain and should not specific to UI (language-context).

You may want to do like this

public enum DownloadStatus
{
    Complete = 1,
    Failed = 2,
    InProgress = 3
}

and using some EnumHelper method to get culture specific description in the UI layer

var downloadStatusString = EnumHelper.GetDescription<DownloadStatus>(DownloadStatus.Complete);

and EnumHelper class will read the culture specific string from the Resource file

public static class EnumHelper
{
    public static string GetDescription<T>(T value)
        where T : struct
    {
        if (!typeof(T).IsEnum)
        {
            throw new ArgumentException("value must be Enum.", "value");
        }

        var name = value.ToString();

        string resourceKey = string.Format(CultureInfo.InvariantCulture, "{0}_{1}", typeof(T).FullName, name);

        object resource = HttpContext.GetGlobalResourceObject("EnumDescriptions", resourceKey, Thread.CurrentThread.CurrentUICulture);
        string description = resource as string ?? name;
        return description;
    }
}

Note: the resource file name is EnumDescriptions and the key must be this conversion YourNamespace.EnumType_EnumValueInString. (I'm using HttpContext to get the resource value and you might want to change it if you are not using ASP.Net.)

Soe Moe
@Soe, your use of generics is perhaps overkill and is unnecessary. All enums are of type `Enum`. You don't want to call string.Format just to concatenate 2 strings.
Robert Paulson