В то время как другие вопросы в основном предлагали элегантное решение для преобразования ваших элементов XML в экземпляр универсального класса, я собираюсь разобраться с последствиями подхода к моделированию класса DataField как универсального типа, подобного DataField < [тип определен в атрибуте элемента XML]> .
После выбора вашего экземпляра DataField в списке вы хотите использовать эти поля. Ее полиморфизм вступает в игру! Вы хотите перебирать свои поля данных и обрабатывать их единообразно. Решения, в которых используются универсальные шаблоны, часто заканчиваются странным переключением / оргией, поскольку в c # нет простого способа связать поведение, основанное на универсальном типе.
Возможно, вы видели такой код (я пытаюсь вычислить сумму всех числовых экземпляров DataField)
var list = new List<DataField>()
{
new DataField<int>() {Name = "int", Value = 2},
new DataField<string>() {Name = "string", Value = "stringValue"},
new DataField<float>() {Name = "string", Value = 2f},
};
var sum = 0.0;
foreach (var dataField in list)
{
if (dataField.GetType().IsGenericType)
{
if (dataField.GetType().GetGenericArguments()[0] == typeof(int))
{
sum += ((DataField<int>) dataField).Value;
}
else if (dataField.GetType().GetGenericArguments()[0] == typeof(float))
{
sum += ((DataField<float>)dataField).Value;
}
// ..
}
}
Этот код - полный беспорядок!
Давайте попробуем полиморфную реализацию с вашим универсальным типом DataField и добавим к нему некоторый метод Sum , который принимает старые some и возвращает (возможно измененную) новую сумму:
public class DataField<T> : DataField
{
public T Value { get; set; }
public override double Sum(double sum)
{
if (typeof(T) == typeof(int))
{
return sum + (int)Value; // Cannot really cast here!
}
else if (typeof(T) == typeof(float))
{
return sum + (float)Value; // Cannot really cast here!
}
// ...
return sum;
}
}
Вы можете себе представить, что ваш итерационный код теперь стал намного понятнее, но у вас все еще есть этот странный оператор switch / if в вашем коде. И вот тут-то и дело: дженерики здесь не помогут, это неправильный инструмент в неправильном месте. Обобщения разработаны в C # для обеспечения безопасности типов времени компиляции во избежание возможных небезопасных операций приведения. Они дополнительно повышают читабельность кода, но это не так:)
Давайте посмотрим на полиморфное решение:
public abstract class DataField
{
public string Name { get; set; }
public object Value { get; set; }
public abstract double Sum(double sum);
}
public class IntDataField : DataField
{
public override double Sum(double sum)
{
return (int)Value + sum;
}
}
public class FloatDataField : DataField
{
public override double Sum(double sum)
{
return (float)Value + sum;
}
}
Полагаю, вам не понадобится слишком много фантазий, чтобы представить, насколько это повышает читабельность / качество вашего кода.
Последний пункт - как создавать экземпляры этих классов. Просто с помощью некоторого соглашения TypeName + «DataField» и Activator:
Activator.CreateInstance("assemblyName", typeName);
Короткая версия :
Обобщения не подходят для вашей проблемы, потому что они не повышают ценность обработки экземпляров DataField. С полиморфным подходом вы можете легко работать с экземплярами DataField!