in serde-generate/src/csharp.rs [672:880]
fn output_struct_or_variant_container(
&mut self,
variant_base: Option<&str>,
variant_index: Option<u32>,
name: &str,
fields: &[Named<Format>],
) -> Result<()> {
// Beginning of class
writeln!(self.out)?;
let fn_mods = if let Some(base) = variant_base {
self.output_comment(name)?;
writeln!(
self.out,
"public sealed class {0}: {1}, IEquatable<{0}>, ICloneable {{",
name, base
)?;
"override "
} else {
self.output_comment(name)?;
writeln!(
self.out,
"public sealed class {0}: IEquatable<{0}>, ICloneable {{",
name
)?;
""
};
let reserved_names = &[];
self.enter_class(name, reserved_names);
// Fields
for field in fields {
self.output_comment(&field.name)?;
writeln!(
self.out,
"public {} {};",
self.quote_type(&field.value),
field.name
)?;
}
if !fields.is_empty() {
writeln!(self.out)?;
}
// Constructor.
writeln!(
self.out,
"public {}({}) {{",
name,
fields
.iter()
.map(|f| format!("{} _{}", self.quote_type(&f.value), &f.name))
.collect::<Vec<_>>()
.join(", ")
)?;
self.out.indent();
for field in fields {
if self.is_nullable(&field.value) {
writeln!(
self.out,
"if (_{0} == null) throw new ArgumentNullException(nameof(_{0}));",
&field.name
)?;
}
writeln!(self.out, "{0} = _{0};", &field.name)?;
}
self.out.unindent();
writeln!(self.out, "}}")?;
// Serialize
if self.generator.config.serialization {
writeln!(
self.out,
"\npublic {}void Serialize(Serde.ISerializer serializer) {{",
fn_mods
)?;
self.out.indent();
writeln!(self.out, "serializer.increase_container_depth();")?;
if let Some(index) = variant_index {
writeln!(self.out, "serializer.serialize_variant_index({});", index)?;
}
for field in fields {
writeln!(
self.out,
"{}",
self.quote_serialize_value(&field.name, &field.value)
)?;
}
writeln!(self.out, "serializer.decrease_container_depth();")?;
self.out.unindent();
writeln!(self.out, "}}")?;
if variant_index.is_none() {
for encoding in &self.generator.config.encodings {
self.output_class_serialize_for_encoding(*encoding)?;
}
}
}
// Deserialize (struct) or Load (variant)
if self.generator.config.serialization {
if variant_index.is_none() {
writeln!(
self.out,
"\npublic static {}{} Deserialize(Serde.IDeserializer deserializer) {{",
fn_mods, name,
)?;
} else {
writeln!(
self.out,
"\ninternal static {} Load(Serde.IDeserializer deserializer) {{",
name,
)?;
}
self.out.indent();
writeln!(self.out, "deserializer.increase_container_depth();")?;
writeln!(
self.out,
"{0} obj = new {0}(\n\t{1});",
name,
fields
.iter()
.map(|f| self.quote_deserialize(&f.value))
.collect::<Vec<_>>()
.join(",\n\t")
)?;
writeln!(self.out, "deserializer.decrease_container_depth();")?;
writeln!(self.out, "return obj;")?;
self.out.unindent();
writeln!(self.out, "}}")?;
if variant_index.is_none() {
for encoding in &self.generator.config.encodings {
self.output_class_deserialize_for_encoding(name, *encoding)?;
}
}
}
// Equality
writeln!(
self.out,
"public override bool Equals(object obj) => obj is {} other && Equals(other);\n",
name
)?;
writeln!(
self.out,
"public static bool operator ==({0} left, {0} right) => Equals(left, right);\n",
name
)?;
writeln!(
self.out,
"public static bool operator !=({0} left, {0} right) => !Equals(left, right);\n",
name
)?;
writeln!(self.out, "public bool Equals({} other) {{", name)?;
self.out.indent();
writeln!(self.out, "if (other == null) return false;")?;
writeln!(self.out, "if (ReferenceEquals(this, other)) return true;")?;
for field in fields {
writeln!(
self.out,
"if (!{0}.Equals(other.{0})) return false;",
&field.name,
)?;
}
writeln!(self.out, "return true;")?;
self.out.unindent();
writeln!(self.out, "}}")?;
// Hashing
writeln!(self.out, "\npublic override int GetHashCode() {{")?;
self.out.indent();
writeln!(self.out, "unchecked {{")?;
self.out.indent();
writeln!(self.out, "int value = 7;")?;
for field in fields {
writeln!(
self.out,
"value = 31 * value + {0}.GetHashCode();",
&field.name
)?;
}
writeln!(self.out, "return value;")?;
self.out.unindent();
writeln!(self.out, "}}")?;
self.out.unindent();
writeln!(self.out, "}}\n")?;
// Clone
if variant_base.is_none() {
// Derived classes can use the method inherited from the base class, it works with derived fields.
writeln!(
self.out,
"/// <summary>Creates a shallow clone of the object.</summary>"
)?;
writeln!(
self.out,
"public {0} Clone() => ({0})MemberwiseClone();\n",
name
)?;
writeln!(self.out, "object ICloneable.Clone() => Clone();\n")?;
}
// Custom code
self.output_custom_code()?;
// End of class
self.leave_class(reserved_names);
writeln!(self.out, "}}")
}