Если вы не инициализировали ссылочный тип и хотите установить или прочитать одно из его свойств, он будет генерировать исключение NullReferenceException.
Пример:
Person p = null;
p.Name = "Harry"; // NullReferenceException occurs here.
Вы можно просто избежать этого, проверив, является ли переменная не нулевой:
Person p = null;
if (p!=null)
{
p.Name = "Harry"; // Not going to run to this point
}
Чтобы полностью понять, почему выбрано исключение NullReferenceException, важно знать разницу между типами значений и ссылочные типы .
Итак, если вы имеете дело со типами значений, NullReferenceExceptions не может произойти. Хотя вам нужно поддерживать оповещение при работе со ссылочными типами!
Только ссылочные типы, как следует из названия, могут содержать ссылки или буквально буквально ничто (или «нуль»). Если типы значений всегда содержат значение.
Типы ссылок (эти должны быть проверены):
Типы значений (вы можете просто игнорировать эти):
Чтобы решить эту проблему, мне пришлось изменить сгенерированные классы:
XmlTextAttribute
из свойства Text
в свойство Items
и добавьте параметр Type = typeof(string)
Text
textField
. В результате сгенерированный код (измененный) выглядит следующим образом:
/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.3038")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(TypeName="StrucDoc.Paragraph", Namespace="urn:hl7-org:v3")]
public partial class StrucDocParagraph {
private StrucDocCaption captionField;
private object[] itemsField;
private string idField;
// ...fields for other attributes...
/// <remarks/>
public StrucDocCaption caption {
get {
return this.captionField;
}
set {
this.captionField = value;
}
}
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute("br", typeof(StrucDocBr))]
[System.Xml.Serialization.XmlElementAttribute("sub", typeof(StrucDocSub))]
[System.Xml.Serialization.XmlElementAttribute("sup", typeof(StrucDocSup))]
// ...other possible nodes...
[System.Xml.Serialization.XmlTextAttribute(typeof(string))]
public object[] Items {
get {
return this.itemsField;
}
set {
this.itemsField = value;
}
}
/// <remarks/>
[System.Xml.Serialization.XmlAttributeAttribute(DataType="ID")]
public string ID {
get {
return this.idField;
}
set {
this.idField = value;
}
}
// ...properties for other attributes...
}
Теперь, если я десериализую XML-элемент, где узел абзаца выглядит следующим образом:
<paragraph>first line<br /><br />third line</paragraph>
В результате массив элементов считывается следующим образом:
itemsField = new object[]
{
"first line",
new StrucDocBr(),
new StrucDocBr(),
"third line",
};
Это именно то, что мне нужно, порядок элементов и их содержимое верны. И если я снова сериализую его, результат снова верен:
<paragraph>first line<br /><br />third line</paragraph>
То, что указывало мне в правильном направлении, было ответом Гийома, я также подумал, что это должно быть возможно так. И затем это было в документации MSDN к XmlTextAttribute
:
Вы можете применить XmlTextAttribute к полю или свойству, которое возвращает массив строк. Вы также можете применить атрибут к массиву типа Object, но вы должны установить свойство Type в строку. В этом случае любые строки, вставленные в массив, сериализуются как XML-текст.
Таким образом, сериализация и десериализация работают исправно, но я не знаю, есть ли какие-либо другие побочные эффекты. Возможно, невозможно создать схему из этих классов с помощью xsd.exe, но мне это все равно не нужно.
У меня была та же проблема, что и у этого, и натолкнулся на это решение изменения .cs, сгенерированного xsd.exe. Хотя это действительно сработало, мне было неудобно изменять сгенерированный код, так как мне нужно было бы это делать, когда я восстанавливал классы. Это также привело к некоторому неудобному коду, который должен был протестировать и передать в XmlNode [] для элементов mailto.
Моим решением было переосмыслить xsd. Я отбросил использование смешанного типа и по существу определил свой собственный смешанный тип.
У меня было это
XML: <text>some text <mailto>me@email.com</mailto>some more text</text>
<xs:complexType name="text" mixed="true">
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="unbounded" name="mailto" type="xs:string" />
</xs:sequence>
</xs:complexType>
и изменено на
XML: <mytext><text>some text </text><mailto>me@email.com</mailto><text>some more text</text></mytext>
<xs:complexType name="mytext">
<xs:sequence>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="text">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string" />
</xs:simpleContent>
</xs:complexType>
</xs:element>
<xs:element name="mailto">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string" />
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:choice>
</xs:sequence>
</xs:complexType>
Мой сгенерированный код теперь дает мне класс myText:
public partial class myText{
private object[] itemsField;
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute("mailto", typeof(myTextTextMailto))]
[System.Xml.Serialization.XmlElementAttribute("text", typeof(myTextText))]
public object[] Items {
get {
return this.itemsField;
}
set {
this.itemsField = value;
}
}
}
порядок элементов теперь сохраняется в сериализации / десериализации, но мне нужно проверить / cast to / program на типы myTextTextMailto
и myTextText
.
Просто подумал, что я брошу это как альтернативный подход, который работал для меня.
Как насчет
itemsField = new object[]
{
"first line",
new StrucDocBr(),
new StrucDocBr(),
"third line",
};
?