views:

569

answers:

4

I have an xml stored property of some control

<Prop Name="ForeColor" Type="System.Drawing.Color" Value="-16777216" />

I want to convert it back as others

System.Type type = System.Type.GetType(propertyTypeString);
object propertyObj = 
  TypeDescriptor.GetConverter(type).ConvertFromString(propertyValueString);

System.Type.GetType("System.Drawing.Color") returns null.

The question is how one can correctly get color type from string

(it will be better not to do a special case just for Color properties)

Update

from time to time this xml will be edited by hand

+2  A: 

Do you have the System.Drawing assembly loaded? Do you have a reference to it?

John Saunders
Yes. I have a reference to it and by the time i reach the line i can see that it is loaded.
jonny
+4  A: 

You need to specify the assembly as well as the type name when using Type.GetType(), unless the type is in mscorlib or the currently executing assembly.

If you know it's in the System.Drawing assembly, you can use Assembly.GetType() instead - or perhaps look in a whole list of possible assemblies:

Type type = candidateAssemblies.Select(assembly => assembly.GetType(typeName))
                               .Where(type => type != null)
                               .FirstOrDefault();

if (type != null)
{
    // Use it
}
else
{
    // Couldn't find the right type
}
Jon Skeet
AFAIK, GetType methods throw a lot... and even if you provide the parameter (throwOnErrors=false) they still throw (arrrrgh), so you'll need to defend the Select's inner lambda, which makes it less readable and clear, etc.
Yacoder
Assembly.GetType only throws in cases where it's really, really bad - if it finds the type name, but a dependency is broken, or if the type name itself is invalid or null. In particular, it *doesn't* throw just because the assembly doesn't contain the type. I think that's probably the desired behaviour.
Jon Skeet
+2  A: 

Are you storing these properties in XML yourself? If so, just write the object's AssemblyQualifiedName instead of just FullName when you create the node. That gives the assembly context information required to load the type from a string using Type.GetType()

Adam Robinson
+1 Good call. If this is an option, it's better than searching through multiple assemblies.
Joe White
It's better in terms of predictability - but worse in terms of readability, especially if it's a signed assembly with a version string etc.
Jon Skeet
Maybe, it's not an issue in the case of System.Drawing, but if you will use QualifiedName for some custom assemblies you may face problems, when those assemblies will be upgraded to another version.
Yacoder
@Jon: I'm not sure I'd agree with the readability aspect. The readability should really only be viewed as whether or not the user can tell what the type IS if they're looking at the XML. The "junk" (version string, PK, etc.) is all at the end. The type and the assembly name are up front in a pretty readable format. For things like this I would HOPE that end user mutability wouldn't be a concern, as users hopefully won't be editing that sort of information by hand.
Adam Robinson
@Yacoder: You could also make the argument that assuming compatibility across versions of assemblies (especially if they're outside of your control) could cause just as many problems. I'm fairly certain, though (but I could be wrong), that unless the assembly is strong signed the binder will use another assembly of the same name even if the version doesn't match, so not strong-signing should make this still work.
Adam Robinson
A: 

Maybe thats not exactly relevant to your problem, but I had a similar one. I needed to serialize/deserialize Color using XmlSerializer. After searching the Internets and combining the wisdom of several authors I came up with the wrapper class:

/// <summary>
/// Color that can be xml-serialized
/// </summary>
public class SerializableColor
{
    public int A { get; set; }
    public int R { get; set; }
    public int G { get; set; }
    public int B { get; set; }
    public int KnownColor { get; set; }

    /// <summary>
    /// Intended for xml serialization purposes only
    /// </summary>
    private SerializableColor() { }

    public SerializableColor(Color color)
    {
        this.A = color.A;
        this.R = color.R;
        this.G = color.G;
        this.B = color.B;
        this.KnownColor = (int)color.ToKnownColor();
    }

    public static SerializableColor FromColor(Color color)
    {
        return new SerializableColor(color);
    }

    public Color ToColor()
    {
        if (KnownColor != 0)
        {
            return Color.FromKnownColor((KnownColor)KnownColor);
        }
        else
        {
            return Color.FromArgb(A, R, G, B);
        }
    }
}

Maybe it can be applied to your situation. You see, Color class sometimes store itself not as a combination of ARGB values, but as a KnownColor enum value... that needs to be preserved during the serialization.

Yacoder