Reputation: 7933
I am having an issue trying to recursively use a generic function for a deserialization algorithm. I am loading in the variables from an XElement by their value. However, if they are no a primitive, I have to recursively do the same operation on that object. However, that object is not the same type as the current one being processed. So for instance if I have
class someObject
{
otherObject obj = new otherObject();
}
class otherObject
{
int someInt = 123;
}
the deserializer recursively goes into the other object. However, the issue is that I have to change the type of the generic method dynamically (ie. I do not know what type it will be at compile time). The algorithm is as follows:
public static T deserialize<T>(XNode element)
where T : new()
{
XElement currentNode = (XElement)element;
FieldInfo[] fields = getFields<T>();
T returnValue = new T();
foreach (FieldInfo field in fields)
{
if (field.FieldType.IsPrimitive)
{
field.SetValue(returnValue, currentNode.Element(field.Name).Value);
}
else
{
//The issue is on the following line
field.SetValue(returnValue, deserialize<???>(currentNode.Element(field.Name).Value));
}
}
}
I have seen plenty of documentation on how to dynamically create typed lists and objects. However, I cannot find anything that deals with dynamically switching the type on a generic method call.
Any help is greatly appreciated! Let me know if am not being clear...
Upvotes: 1
Views: 1074
Reputation: 8505
Try this, but you have to mark the class with attributes DataContract, DataMember
static readonly XmlWriterSettings ws = new XmlWriterSettings()
{
OmitXmlDeclaration = true,
Encoding = System.Text.Encoding.UTF8
};
static XElement ToXElement<T>(T obj)
{
StringBuilder sb = new StringBuilder();
Type valorType = obj.GetType();
using (var writer = XmlDictionaryWriter.Create(sb, ws))
{
DataContractSerializer s = new DataContractSerializer(typeof(T));
s.WriteObject(writer, obj);
writer.Flush();
writer.Close();
}
return XElement.Parse(sb.ToString());
}
static T ToObj<T>(XElement node)
{
string xml = node.ToString(SaveOptions.DisableFormatting);
T respuesta = default(T);
DataContractSerializer dcs = new DataContractSerializer(typeof(T));
using (StringReader strReader = new StringReader(xml))
{
using (XmlReader xmlReader = new XmlTextReader(strReader))
{
respuesta = (T)dcs.ReadObject(xmlReader, false);
}
}
return respuesta;
}
Test:
[DataContract]
public class A
{
[DataMember]
public int Prop { get; set; }
}
var node = ToXElement(12);
int obj = ToObj<int>(node);
var node2 = ToXElement(new A { Prop = 12 });
A obj2 = ToObj<A>(node2);
Upvotes: 0
Reputation: 311255
I would make the generic method call another private non-generic method that uses a different means of creating the instance instead of new T()
. The outer generic method will be convenient for a caller of the method, so they don't have to cast the response. Internally, your code will be simpler.
Note that the .NET framework's deserialisation methods all at least have overloads that take a Type
instance instead of a generic type parameter (<T>
). This is for the reason you're discovering -- sometimes you have the type as an object, and then you can't (sensibly) call a generic method and pass that type parameter.
Upvotes: 1