fn output_struct_or_variant_container()

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, "}}")
    }