tags:

views:

434

answers:

6

A am encountering a problem which is how do I convert input strings like "RED" to the actual Color type Color.Red in C#. Is there a good way to do this?

I could think of using a switch statement and cases statement for each color type but I don't think that is clever enough.

+5  A: 
System.Drawing.Color myColor = System.Drawing.ColorTranslator.FromHtml("Red");

(Use my method if you want to accept HTML-style hex colors.)

Larsenal
+12  A: 
 Color red = Color.FromName("Red");   

The MSDN doesn't say one way or another, so there's a good chance that it is case-sensitive.

As far as I can tell, ColorTranslator.FromHtml is also.

If Color.FromName cannot find a match, it returns new Color(0,0,0);

If ColorTranslator.FromHtml cannot find a match, it throws an exception.

UPDATE:

Since you're using Microsoft.Xna.Framework.Graphics.Color, this gets a bit tricky:

using XColor = Microsoft.Xna.Framework.Graphics.Color;
using CColor = System.Drawing.Color;

 CColor clrColor = CColor.FromName("Red"); 
 XColor xColor = new XColor(clrColor.R, clrColor.G, clrColor.B, clrColor.A);
James Curran
Hey James,thx for your comment.Since I am developing this in the XNA GameStudio,after I input your code,the program complains: Error 1 'Microsoft.Xna.Framework.Graphics.Color' does not contain a definition for 'FromName' and no extension method 'FromName' accepting a first argument of type 'Microsoft.Xna.Framework.Graphics.Color' could be found (are you missing a using directive or an assembly reference?) C:\Users\Guoguo\Desktop\MapWorld2\MapWorld\GameObject.cs 194 27 MapWorld Do you what the error is?Thanks.
Robert
+1 for mentioning the different behavior when a match isn't found.
Davy8
Microsoft.Xna.Framework is not the right namespace. Use System.Drawing
StingyJack
This is a method found in System.Drawing.Color, not (apparently) Microsoft.Xna.Framework.Graphics.Color.
Larsenal
@StingyJack: You can't ask the OP to change which type he's interested in! Admittedly it would have been nice to have been *told* what type he was interested in to start with...
Jon Skeet
The edit assumes the set of colors in `System.Drawing.Color` is the same as that in the XNA `Color` type. That may or may not be the case... and may or may not be important (the OP may be happy with the range of colors in `System.Drawing`).
Jon Skeet
Thanks all guys for your input!I got the Jame's final version of code working,and I will study two other methods posted.
Robert
A: 

Hi Robert,

I've used something like this before:

        public static T CreateFromString<T>(string stringToCreateFrom) {

        T output = Activator.CreateInstance<T>();

        if (!output.GetType().IsEnum)
            throw new IllegalTypeException();

        try {
            output = (T) Enum.Parse(typeof (T), stringToCreateFrom, true);
        }
        catch (Exception ex) {
            string error = "Cannot parse '" + stringToCreateFrom + "' to enum '" + typeof (T).FullName + "'";
            _logger.Error(error, ex);
            throw new IllegalArgumentException(error, ex);
        }

        return output;
    }
Skyler
It's not an enum.
Jon Skeet
@Jon I got mixed up with ConsoleColor. The same logic could still apply though... right? Instead of Enum.Parse() he can do a case insensitive compare on property names and return the result. (obviously removing the IsEnum check).
Skyler
@Skyler: I think finding the property by reflection each time would be relatively painful. Better, IMO, to build a dictionary once (as per my answer).
Jon Skeet
@Jon Yeah I saw it after I refreshed.
Skyler
+3  A: 

(It would really have been nice if you'd mentioned which Color type you were interested in to start with...)

One simple way of doing this is to just build up a dictionary via reflection:

public static class Colors
{
    private static readonly Dictionary<string, Color> dictionary =
        typeof(Color).GetProperties(BindingFlags.Public | 
                                    BindingFlags.Static)
                     .Where(prop => prop.PropertyType == typeof(Color))
                     .ToDictionary(prop => prop.Name,
                                   prop => (Color) prop.GetValue(null, null)));

    public static Color FromName(string name)
    {
        // Adjust behaviour for lookup failure etc
        return dictionary[name];
    }
}

That will be relatively slow for the first lookup (while it uses reflection to find all the properties) but should be very quick after that.

If you want it to be case-insensitive, you can pass in something like StringComparer.OrdinalIgnoreCase as an extra argument in the ToDictionary call. You can easily add TryParse etc methods should you wish.

Of course, if you only need this in one place, don't bother with a separate class etc :)

Jon Skeet
Looks like this is the best way to answer the reverse of this question: http://stackoverflow.com/questions/3392030/convert-a-xna-color-object-to-a-string
Bennor McCarthy
+2  A: 

Since the OP mentioned in a comment that he's using Microsoft.Xna.Framework.Graphics.Color rather than System.Drawing.Color you can first create a System.Drawing.Color then convert it to a Microsoft.Xna.Framework.Graphics.Color

public static Color FromName(string colorName)
{
    System.Drawing.Color systemColor = System.Drawing.Color.FromName(colorName);   
    return new Color(systemColor.R, systemColor.G, systemColor.B, systemColor.A); //Here Color is Microsoft.Xna.Framework.Graphics.Color
}
Davy8
The second line should be: Color xnaColor = new Color(systemColor.R, systemColor.G, systemColor.B, systemColor.A);But I belive this is the simplest way to accomplish what Robert asked.
Romias
@Romias thanks, fixed.
Davy8
...and a proper `return` statement should be added too :)
Peter Lillevold
and fixed that as well
Davy8
A: 

I haven't used XNA, so I'm not able to test this, but you should be able to do it with a TypeConverter:

System.ComponentModel.TypeDescriptor.GetConverter(typeof(Microsoft.Xna.Framework.Graphics.Color)).ConvertFromString("Red")

Don't use Reflection, it's ugly and slow (if you're not careful).

If you're doing this often, you might want to cache the TypeConverter.

Bennor McCarthy
@Bennor: Assuming your comment about reflection is referring to my answer, you should note that it only uses reflection the first time the class is accessed. After that, it's using a simple dictionary lookup.
Jon Skeet
Yeah, fair comment. I just prefer to avoid it if I can. Wasn't really directed at your comment - more of a general statement.
Bennor McCarthy
I tend to take the approach of finding the right tool for the job - in this case, I know that reflection will definitely work, whereas I don't know whether there's a converter for `Color`. Also, in terms of efficiency, you'll need to cast back from `object` to `Color` - so you'll get a boxing/unboxing penalty too.
Jon Skeet
Yeah, good call. I overlooked that.
Bennor McCarthy