0

Given the example code below, I'd like to get the runtime type of T inside a generic method (in this case retrieveData). When I create an XMLFilePersisting I use the interface, namely ITransferable rather than the implementing Types since in my client I want to have a list of all of them together:

List<XMLFilePersisting<ITransferable>> allThem; 

So if in retrieveData I do typeof(T) that should return ITransferable which doesn't give me enough info to load the items from the file. The only way I could figure out how to do this was by passing an instance of the implementor of ITransferable in the constructor, but this kind of feels like there should be a better way. Suggestions?

public interface IPersisting<T> { List<T> retrieveData(); bool persistData(List<T> lst); } public interface ITransferable { Type getRuntimeType(); } public class XMLFilePersisting<T> : IPersisting<T> where T : ITransferable { private readonly T defaultT; //... public XMLFilePersisting(string thefile, string thepath, T def) { //... defaultT = def; } ... public List<T> retrieveData() { List<T> retVal = new List<T>(); Type runType = defaultT.getRuntimeType(); string elemName = runType.Name; using (FileStream fs = new FileStream(FQ_FILE_PATH, FileMode.Open, FileAccess.Read)) { using (XmlReader reader = XmlReader.Create(fs)) { //below line won't work, typeof resolves at compileTime //XmlSerializer xmlSer = new XmlSerializer(typeof(T)); XmlSerializer xmlSer = new XmlSerializer(runType); if (reader.ReadToFollowing(elemName)) { //go to the first test, skipping over ListofT do { T testVal = (T)xmlSer.Deserialize(reader); retVal.Add(testVal); } while (reader.ReadToNextSibling(elemName)); } } //end using xmlreader } //end using FileStream return retVal; } //end retrieveData } //end class XMLFilePersisting 

Additional info:

Client code looks like below. As you can see I need all

IPersisting<ITransferable> 

instances, but the problem is in retrieveData, that makes typeof(T) = ITransferable which doesn't give me enough info to do the deserialization. That is why I pass concrete implmentations of ITransferable to the constructor (MyClass1, MyClass2). This seems to work, but feels like a hack.

IPersisting<ITransferable> xfpMC1 = new XMLFilePersisting<ITransferable>("persistedMC1.xml", myTempDirectory, new MyClass1()); IPersisting<ITransferable> xfpMC2 = new XMLFilePersisting<ITransferable>("persistedMC2.xml", myTempDirectory, new MyClass2()); 

A

6
  • 2
    First thing to change: start following .NET naming conventions. It'll make it simpler for others to read your code, if you meet their naming expectations. Commented Feb 7, 2015 at 7:56
  • Next, it's not at all clear where you would be passing the information about which actual type you want. Your "When I create an XMLFilePersisting I use the interface, namely ITransferable rather than the implementing Types since in my client I want to have a list of all of them together" doesn't explain much to me. Are you creating multiple instances of XMLFilePersisting? If so, why not create a single instance for each concrete type, then build a big List<ITransferable> from the results? Commented Feb 7, 2015 at 7:58
  • Sorry. I edited my question to better show the relevant part from my calling code Commented Feb 7, 2015 at 8:34
  • Well we still don't know why you want them to be IPersisting<ITransferable> rather than an IPersisting<MyClass1> and an IPersisting<MyClass2> which would obviously solve the issue. Commented Feb 7, 2015 at 8:35
  • @JonSkeet at the end of the day I'd prefer they all go into a single strongly typed List Commented Feb 7, 2015 at 8:50

1 Answer 1

3

I would suggest that you make each XMLFilePersisting use the specific concrete type, but then combine the results into a List<ITransferable>. For example:

// Names changed to be more conventional var class1Loader = new XmlFilePersister<MyClass1>("MC1.xml", myTempDirectory"); var class2Loader = new XmlFilePersister<MyClass2>("MC2.xml", myTempDirectory"); // Could do all of this in one statement... note that this uses the // covariance of IEnumerable<T> IEnumerable<ITransferable> class1Results = class1Loader.RetrieveData(); IEnumerable<ITransferable> class2Results = class2Loader.RetrieveData(); var allResults = class1Results.Concat(class2Results).ToList(); 

Having misunderstood the question slightly, if it's the persisters you want to be in a list, you could make XMLFilePersisting<T> implement IPersisting<ITransferable> - although then you'd have problems when you try to store the data instead of reading it... because you'd need to cast from ITransferable to T, which could obviously fail at execution time.

Fundamentally, I wonder whether you should have two interfaces: IDeserializer<out T> and ISerializer<in T>. With those covariant and contravariant interfaces, you could easily have a List<IDeserializer<ITransferable>> without losing information or needing execution-time checking.

Sign up to request clarification or add additional context in comments.

4 Comments

do you have a typo, when twice call class1Loader.RetrieveData(); and for class2Results should be called class2Loader.RetrieveData();?
Unfortunately I don't think that will work for me as I need a List<IPersisting<ITransferable>> rather than a List<ITransferable>. Since IPersisting is invariant (right?) I can't upcast from XMLFilePersisting<MyClass1> to IPersisting<ITransferable> Other threads have pointed to reflection but I'd rather just stay with my 'hack' of storing an arbitrary T reference.
@publicwireless: Ah, I see. How about making XMLFilePersisting<T> just implement IPersisting<ITransferable>? Or you could make it generic in two types... it's a bit hard to tell without knowing more context.
@publicwireless: I've edited my answer to give a bit more detail.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.