Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I serialize a C# Type object?

I'm trying to serialize a Type object in the following way:

Type myType = typeof (StringBuilder); var serializer = new XmlSerializer(typeof(Type)); TextWriter writer = new StringWriter(); serializer.Serialize(writer, myType); 

When I do this, the call to Serialize throws the following exception:

"The type System.Text.StringBuilder was not expected. Use the XmlInclude or SoapInclude attribute to specify types that are not known statically."

Is there a way for me to serialize the Type object? Note that I am not trying to serialize the StringBuilder itself, but the Type object containing the metadata about the StringBuilder class.

like image 913
Brian Sullivan Avatar asked Aug 15 '08 14:08

Brian Sullivan


People also ask

How do I make my AC class serializable?

The easiest way to make a class serializable is to mark it with the SerializableAttribute as follows. The following code example shows how an instance of this class can be serialized to a file. MyObject obj = new MyObject(); obj. n1 = 1; obj.

What objects can be serialized?

To serialize an object means to convert its state to a byte stream so way that the byte stream can be reverted back into a copy of the object. A Java object is serializable if its class or any of its superclasses implements either the java. io. Serializable interface or its subinterface, java.

When should I serialize data?

If data is not present on the local member, the system will retrieve that data from another member. This requires serialization for use cases such as: Adding key/value objects to a map. Putting items into a queue, set, or list.


2 Answers

I wasn't aware that a Type object could be created with only a string containing the fully-qualified name. To get the fully qualified name, you can use the following:

string typeName = typeof (StringBuilder).FullName; 

You can then persist this string however needed, then reconstruct the type like this:

Type t = Type.GetType(typeName); 

If you need to create an instance of the type, you can do this:

object o = Activator.CreateInstance(t); 

If you check the value of o.GetType(), it will be StringBuilder, just as you would expect.

like image 68
Brian Sullivan Avatar answered Oct 04 '22 21:10

Brian Sullivan


I had the same problem, and my solution was to create a SerializableType class. It freely converts to and from System.Type, but it serializes as a string. All you have to do is declare the variable as a SerializableType, and from then on you can refer to it as System.Type.

Here is the class:

// a version of System.Type that can be serialized [DataContract] public class SerializableType {     public Type type;      // when serializing, store as a string     [DataMember]     string TypeString     {         get         {             if (type == null)                 return null;             return type.FullName;         }         set         {             if (value == null)                 type = null;             else             {                 type = Type.GetType(value);             }         }     }      // constructors     public SerializableType()     {         type = null;     }     public SerializableType(Type t)     {         type = t;     }      // allow SerializableType to implicitly be converted to and from System.Type     static public implicit operator Type(SerializableType stype)     {         return stype.type;     }     static public implicit operator SerializableType(Type t)     {         return new SerializableType(t);     }      // overload the == and != operators     public static bool operator ==(SerializableType a, SerializableType b)     {         // If both are null, or both are same instance, return true.         if (System.Object.ReferenceEquals(a, b))         {             return true;         }          // If one is null, but not both, return false.         if (((object)a == null) || ((object)b == null))         {             return false;         }          // Return true if the fields match:         return a.type == b.type;     }     public static bool operator !=(SerializableType a, SerializableType b)     {         return !(a == b);     }     // we don't need to overload operators between SerializableType and System.Type because we already enabled them to implicitly convert      public override int GetHashCode()     {         return type.GetHashCode();     }      // overload the .Equals method     public override bool Equals(System.Object obj)     {         // If parameter is null return false.         if (obj == null)         {             return false;         }          // If parameter cannot be cast to SerializableType return false.         SerializableType p = obj as SerializableType;         if ((System.Object)p == null)         {             return false;         }          // Return true if the fields match:         return (type == p.type);     }     public bool Equals(SerializableType p)     {         // If parameter is null return false:         if ((object)p == null)         {             return false;         }          // Return true if the fields match:         return (type == p.type);     } } 

and an example of usage:

[DataContract] public class A {      ...      [DataMember]     private Dictionary<SerializableType, B> _bees;      ...      public B GetB(Type type)     {         return _bees[type];     }      ...  } 

You might also consider using AssemblyQualifiedName instead of Type.FullName - see comment by @GreyCloud

like image 26
hypehuman Avatar answered Oct 04 '22 21:10

hypehuman