Во-первых, вместо сохранения типа List<T>
в словаре, просто сохраните базовый тип generi c:
private static readonly Dictionary<string, Type> listTypeByFileName = new Dictionary<string, Type> {
{"a.xml", typeof(A)},
{"b.xml", typeof(B)}
// etc.
Это немного облегчит будущие шаги. При десериализации создайте тип списка generi c. После получения типа из словаря вы можете выполнить:
var listType = typeof(List<>).MakeGenericType(typeRetrievedFromDictionary);
После того, как вы десериализовали его, присвойте ему значение IList
. Это фактически приводит его к списку object
. Это нормально. Поскольку вы десериализовали, используя указанный тип c, каждый элемент в списке будет иметь ожидаемый тип.
Создайте словарь для безопасных с точки зрения типов методов, которые вы хотите вызывать каждый раз в списке.
Dictionary<Type, Action<object>> methodsToInvokeByType;
Добавление методов в словарь:
doSometingMethods.Add(typeof(A), dataItem => DoSomethingWithA((A)dataItem));
doSometingMethods.Add(typeof(B), dataItem => DoSomethingWithB((B)dataItem));
Теперь, когда у вас есть IList
полный объектов, вы получаете безопасный для вызова метод для вызова:
var methodToInvoke = methodsToInvokeByType[typeRetrievedFromDictionary];
Затем сделайте это:
foreach(object itemInList in list) // this is your deserialized list cast as IList
{
methodToInvoke(itemInList);
}
Поэтому, если тип A
, вы будете вызывать
DoSomethingWithA ((A) itemInList)
Это не красиво. Соединение между кодом, использующим объекты, и типом и кодом типа safe-generi c может быть грязным. Но в конечном итоге цель состоит в том, что какими бы ни были эти окончательные методы - DoSomethingWithA
, DoSomethingWithB
и др. c., По крайней мере, они являются типобезопасными.
Вы можете упростить еще немного:
Создать класс, который десериализует список и передает его методу для обработки, а также интерфейсу:
public interface IXmlFileProcessor
{
void Process(byte[] xmlFile);
}
public class XmlFileProcessor<T> : IXmlFileProcessor
{
private readonly Action<T> _doSomething;
public XmlFileProcessor(Action<T> doSomething)
{
_doSomething = doSomething;
}
public void Process(byte[] xmlFile) // or string or whatever
{
// deserialize into a List<T>
foreach (T item in deserializedList)
_doSomething(item);
}
}
Затем создайте Dictionary<Type, IXmlFileProcessor>
и заполните его:
fileProcessors.Add(typeof(A), new XmlFileProcessor<A>(SomeClass.DoSomethingWithA));
fileProcessors.Add(typeof(B), new XmlFileProcessor<B>(SomeClass.DoSomethingWithB));
Этот подход (внедрение Action
) предназначен для того, чтобы сохранить метод "что-то сделать" отделенным от класса, отвечающего за десериализацию. DoSomething
также может быть обобщенным c методом в XmlFileProcessor<T>
. Есть разные способы составить эти классы и добавить их в этот словарь. Но в любом случае, определив тип, вы просто извлекаете правильный процессор c, определяющий тип, из словаря, передаете в него свой файл, и он делает все остальное.
Этот подход соединяет общий / не -generi c пробел путем создания класса - XmlFileProcessor<T>
- generi c, но с реализацией интерфейса не-generi c. Он работает до тех пор, пока вы делаете шаги (используя словарь), чтобы убедиться, что вы выбираете правильную реализацию для любого типа, который вы десериализуете.