tags:

views:

84

answers:

5

Ok so the class I want to use is declared with:

public static class ObjectXMLSerializer<T> where T : class

I have many objects that I want to serialize, but I do not know their "class"

object myclass = new MyNamespace.MyClass() as object;

How do I do the following... ?

ObjectXMLSerializer< ? >.Save(myclass,"output.xml");

I can't do this because the type that is expected, is "class"

ObjectXMLSerializer< myclass.GetType() >.Save(myclass,"output.xml");

And this just wouldnt work ...

ObjectXMLSerializer< object >.Save(myclass,"output.xml");

Any thoughts would be appreciated!

+7  A: 

You're trying to use generics for something it isn't designed for.

Generics are meant to give compile-time safety (and express information about the API at compile-time). You don't know the types involved at compile-time, so you've got a problem.

Options:

  • Use a non-generic API
  • Call the generic API via reflection
  • Redesign your code so that the relevant method does know the type at compile-time (e.g. make the method that calls Save generic too)
Jon Skeet
I am requesting a new feature on SO. A begrudging upvote button. One that implies "Curses! I shake my fist at you Jon Skeet!" -- All in good fun though.
Josh
Thanks Jon, especially for such a quick and precise response!
Chris
+1  A: 

You could try this without generics:

public static class ObjectXMLSerializer
{
    public static void Save(IXmlSerializable myObject, string fileName) 
    {
        // whatever
    }
}

Although, depending on what you're trying to do, you might be better off just using the framework's XmlSerializer instead of writing your own.

Anna Lear
An object doesn't need to implement IXmlSerializable to be serialized to XML... this interface is used only to provide custom XML serialization
Thomas Levesque
@Thomas: Absolutely. But I figured it would be an easy way to narrow down the scope of objects that could be passed to this method. It'd probably be best replaced by a custom interface if the OP goes that route.
Anna Lear
A: 

I'm recommending an interface IXmlSerializable with the method Serialize() exposed. If you need to refer to them generically (without knowing it's ClassA or ClassB , you can cast or box them to the interface and call the method.

Usually, I just attribute my objects with Serializable and make sure all the properties are serializable or attribute the property with XmlIgnore / Nonserialized

[Serializable]
public class MyClass
{
     [Nonserialized]
     private DataTable _myProperty;
     [XmlIgnore]
     public DataTable MyProperty { get; set; }
}
Brad
A: 

Don't use generics if XML serialization is all that you care about:

public static class ObjectXMLSerializer { 
  public static void Save(object objectToSerialize, string fileName) { 
    // ...
  } 
} 

Alternatively, look at the XmlSerializer class, it might already cover your requirements:

public static class ObjectXMLSerializer {
  public static void Save(object objectToSerialize, string fileName) {
    var serializer = new XmlSerializer(objectToSerialize.GetType());
    using (var stream = File.OpenWrite(fileName)) {
      serializer.Serialize(stream, objectToSerialize);
    }
  }
}

To deserialize, though, since you must know the compile-time type of the object that you want, you could use generics on the deserialization method:

public static class ObjectXMLDeserializer {
  public static T Load<T>(string fileName) { 
    var serializer = new XmlSerializer(typeof(T));
    using (var stream = File.OpenRead(fileName)) {
      return (T)serializer.Deserialize(stream);
    }
  } 
}
Jordão
These two functions make pretty decent extention methods as well.
asawyer
@asawyer: absolutely! Take a look at [this post](http://codecrafter.blogspot.com/2010/02/c-quasi-mixins-pattern.html) for a different take on this subject.
Jordão
That was an interesting read, thanks.
asawyer
A: 

Despite the fact that you might be doing it wrong, you can construct a generic type and an instance of generic type using reflection. For example, if I would like to create a List<int> I can write

Type t = typeof(List<>).MakeGenericType(typeof(int));
object list = Activator.CreateInstance(t);
// add an integer to list and get Count property        
t.GetMethod("Add").Invoke(list, new object[] {3});
int count = (int) t.GetProperty("Count").GetValue(list, null);

... and that is why everybody would suggest redesigning your class.

tia
that's some painful code...
Chris