2015-02-07 3 views
0

Учитывая приведенный ниже пример кода, я хотел бы получить тип времени выполнения T внутри общего метода (в данном случае retrieveData). Когда я создаю XMLFilePersisting я использую интерфейс, а именно ITransferable, а не типы исполнителей, так как в моем клиенте я хочу иметь список всех из них вместе:Лучший способ получить время работы Тип T?

List<XMLFilePersisting<ITransferable>> allThem; 

Так что, если в retrieveData я TypeOf (T) который должен вернуть ITransferable, который не дает мне достаточно информации для загрузки элементов из файла. Единственный способ понять, как это сделать, - это передать экземпляр конструктора ITransferable в конструкторе, но это похоже на то, что должен быть лучший способ. Предложения?

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 

Дополнительная информация:

Клиентский код выглядит, как показано ниже. Как вы можете видеть, мне нужно все

IPersisting<ITransferable> 

экземпляров, но проблема заключается в retrieveData, что делает TypeOf (T) = ITransferable, который не дает мне достаточно информации, чтобы сделать десериализации. Вот почему я передаю конкретные импликации ITransferable для конструктора (MyClass1, MyClass2). Кажется, это работает, но кажется, что это взломать.

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

+2

Первое, что нужно изменить: начать следующие соглашения об именах .NET. Это упростит, если другие прочтут ваш код, если вы встретите их ожидания именования. –

+0

Далее, это совсем не ясно, где вы будете передавать информацию о том, какой фактический тип вы хотите. Ваш «Когда я создаю XMLFilePersisting, я использую интерфейс, а именно ITransferable, а не реализующие типы, поскольку в моем клиенте я хочу иметь список всех из них вместе», не объясняет мне многое. Вы создаете несколько экземпляров 'XMLFilePersisting'? Если да, почему бы не создать один экземпляр для каждого конкретного типа, а затем построить большой «List » из результатов? –

+0

Извините. Я отредактировал мой вопрос, чтобы лучше показать соответствующую часть из моего кода вызова –

ответ

3

Я хотел бы предложить, что вы делаете каждый XMLFilePersisting использовать конкретный конкретный тип, но затем объединить результаты в List<ITransferable>. Например:

// 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(); 

Слегка не понял вопрос, если это persisters вы хотите быть в списке, вы могли бы сделать XMLFilePersisting<T> реализовать IPersisting<ITransferable> - хотя тогда бы возникли проблемы при попытке магазина данные вместо того, чтобы читать его ... потому что вам нужно было бы отличить от ITransferable до T, что, очевидно, могло не работать во время выполнения.

По существу, интересно, имеете ли вы два интерфейса: IDeserializer<out T> и ISerializer<in T>. С этими ковариантными и контравариантными интерфейсами вы можете легко получить List<IDeserializer<ITransferable>> без потери информации или проверки времени выполнения.

+0

у вас есть опечатка, когда вы дважды вызываете 'class1Loader.RetrieveData(); 'и для' class2Results' следует называть 'class2Loader.RetrieveData();'? – Grundy

+0

@ Грюнди: Да, исправлено. –

+0

К сожалению, я не думаю, что это сработает для меня, поскольку мне нужен «Список >», а не 'List '. Поскольку IPersisting является инвариантным (правильно?), Я не могу пересказывать из 'XMLFilePersisting ' в 'IPersisting ' Другие потоки указывают на отражение, но я бы предпочел просто остаться с моим «взломом» для хранения произвольной ссылки T. –