On numerous occasions I’ve been involved in projects, where I’ve had an instance of a given object type present in one namespace and the need to convert it to an object type with exactly the same signature, but in another namespace.
Usually, in a scenarios of dealing with web services – where different web services, logically refer to the same types, but the proxy classes are generated in different namespaces – making the incompatible.
The non-technical approach, would be to convert the instance types with helper methods. Copying each data field/property one-by-one. For large and deeply nested structures, this quickly becomes a dead end.
To solve this problem, I use the less-known serialization trick:
Serialize the source instance
Deserialize the source instance, but to the destination instance type
This of course requires the types to be serializable, if you’re dealing with web service proxies – this is not an issue – as these will most probably already be serializable 🙂
The C# code for doing the conversion:
///
<summary>
/// Converts a given instance (of a given type) to the same type, but present in another namespace
/// (requires types to be serializable).
/// </summary>
/// <typeparam name="T">The type to convert to</typeparam>
/// <param name="instance">The instance containing the source type</param>
/// <returns>The covnerted type</returns>
private static T ConvertType<T>(object instance)
{
if (instance == null)
{
throw new ArgumentNullException("instance");
}
var typeSource = instance.GetType();
var typeDestination = typeof(T);
T result = default(T);
// We're using a Memorystream for the serialization magic
using (var ms = new MemoryStream())
{
// Create the serializer for the incoming type
var serializer = new XmlSerializer(typeSource);
// Create a XML text writer, and serialize the incomming instance to memory
var tw = new XmlTextWriter(ms, Encoding.UTF8);
serializer.Serialize(tw, instance);
// Rewind the MemoryStream to the beginning.
ms.Position = 0;
// Now, create the deserializer for the destination type
var deserializer = new XmlSerializer(typeDestination);
using (var reader = new XmlTextReader(ms))
{
try
{
result = (T)deserializer.Deserialize(reader);
}
catch (Exception ex)
{
throw new ApplicationException(String.Format("Converting from type: {0}->{1} failed", typeSource.FullName, typeDestination.FullName), ex);
}
}
}
return result;
}
Example:
namespace OneNamespace
{
[Serializable]
public class Person
{
public string Name;
public int Age;
}
}
namespace OtherNamespace
{
[Serializable]
public class Person
{
public string Name;
public int Age;
}
}
var person1 = new OneNamespace.Person() {Name = "Henrik", Age = 25};
// Obviously, casting is NOT an option :-)
//OtherNamespace.Person person2 = (OtherNamespace.Person)person1;
var person2 = ConvertType<OtherNamespace.Person>(person1);