У меня есть решение для вас, но, к сожалению, оно не соответствует вашим ожиданиям. Я не знаю, пробовали ли вы это, но я надеюсь, что это поможет вам, по крайней мере.
Поправь меня, если я ошибаюсь, но не похоже, что есть поддержка того, что ты пытаешься достичь, если только ты не развернешь свой собственный десериализатор.
Что может отсутствовать, так это способ информирования сериализатора Xml об использовании универсального класса ReportParameter<T>
и о том, какие типы T
он должен учитывать.
Таким образом, вместо того, чтобы использовать подход «Общие параметры», я вручную прокрутил эти классы.
public class ReportParameterOfInt32 : ReportParameter
{
int _value;
[XmlIgnore]
public new int Value
{
get { return _value; }
set
{
base.Value = value;
_value = value;
}
}
}
public class ReportParameterOfDateTime : ReportParameter
{
DateTime _value;
[XmlIgnore]
public new DateTime Value
{
get { return _value; }
set
{
base.Value = value;
_value = value;
}
}
}
Обновлен ReportParameters
(который я догадался, как он выглядит, поскольку он не был указан в вашем вопросе):
public class ReportParameters
{
[XmlArrayItem(typeof(ReportParameterOfInt32))]
[XmlArrayItem(typeof(ReportParameterOfDateTime))]
public ReportParameter[] Parameters { get; set; }
}
Упростил сериализатор и написал десериализатор:
private static string Serialize(ReportParameters parameters)
{
XmlSerializer xsSubmit = new XmlSerializer(typeof(ReportParameters));
string xml = string.Empty;
using (var sww = new StringWriter())
{
using (var writer = XmlWriter.Create(sww))
{
xsSubmit.Serialize(writer, parameters);
xml = sww.ToString();
return xml;
}
}
}
private static ReportParameters Deserialize(string xml)
{
XmlSerializer xsSubmit = new XmlSerializer(typeof(ReportParameters));
using (var reader = new StringReader(xml))
{
return (ReportParameters)xsSubmit.Deserialize(reader);
}
}
Написал тестовый код, который затем выполнялся, как и ожидалось:
var xml = Serialize(
new ReportParameters
{
Parameters = new ReportParameter[]
{
new ReportParameterOfInt32 { Name = "Test", Value = 4 },
new ReportParameterOfDateTime { Name = "Startdate", Value = new DateTime(2019, 04, 05, 22, 52, 25) }
}
});
var obj = Deserialize(xml);
Производство:
<?xml version="1.0" encoding="utf-16"?>
<ReportParameters xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Parameters>
<ReportParameterOfInt32>
<Name>Test</Name>
<Value xsi:type="xsd:int">4</Value>
</ReportParameterOfInt32>
<ReportParameterOfDateTime>
<Name>Startdate</Name>
<Value xsi:type="xsd:dateTime">2019-04-05T22:52:25</Value>
</ReportParameterOfDateTime>
</Parameters>
</ReportParameters>
Я знаю, что вы можете чувствовать себя немного разочарованным, однако я думаю, что вы можете просто использовать оболочки, чтобы гарантировать правильную запись в базовый тип без необходимости сериализации универсального типа, который, как мы надеемся, удовлетворяет вашему требованию «SQL-инъекции» но у вас все еще будет проблема с строк .
Вам необходимо убедиться, что вы экранировали все символы , которые сделают возможным внедрение SQL, поскольку строки будут по-прежнему уязвимы для этого при создании оператора SQL для отправки в БД. Я уверен, что вы можете Google, как это сделать (так как я думаю, что это совершенно другое обсуждение вашего вопроса).
Таким образом, вместо обновления нового ReportParameter вы можете иметь:
private ReportParameter GetReportParameter<T>(string name, T value)
{
return new ReportParameter
{
Name = name,
Value = value
};
}
Затем при сериализации:
var xml = Serialize(
new ReportParameters
{
Parameters = new ReportParameter[]
{
GetReportParameter("Test", 4),
GetReportParameter("Startdate", new DateTime(2019, 04, 05, 22, 52, 25))
}
});
Теперь вы устраняете необходимость в различных типах классов ReportParameterOfInt32
и ReportParameterOfDateTime
.
Что касается десериализации XML, вам может понадобиться добавить отдельное поле Type
в ваш ReportParameter
, если вы собираетесь хранить какую-либо информацию о дизайнере отчетов. Тем не менее, я не знаю точно, каковы ваши требования, но это может помочь вам во время выполнения определить Type
свойства Value
более простым способом.
UPDATE
@ Патрик Б обнаружил, что можно использовать XmlArrayItem
для указания версии Generic Type ReportParameter
для достижения этой цели. Имеет смысл.
* +1054 * Пример:
public class ReportParameters
{
[XmlArrayItem(Type = typeof(ReportParameter<int>))]
[XmlArrayItem(Type = typeof(ReportParameter<int?>))]
[XmlArrayItem(Type = typeof(ReportParameter<DateTime>))]
public List<ReportParameter> Parameters { get; set; } = new List<ReportParameter>();
}