void t_netstd_generator::generate_netstd_union_definition()

in compiler/cpp/src/thrift/generate/t_netstd_generator.cc [1655:1852]


void t_netstd_generator::generate_netstd_union_definition(ostream& out, t_struct* tunion)
{
    // Let's define the class first
    start_netstd_namespace(out);

    generate_deprecation_attribute(out, tunion->annotations_);
    out << indent() << "public abstract partial class " << normalize_name(tunion->get_name()) << " : TUnionBase" << '\n';
    out << indent() << "{" << '\n';
    indent_up();

    out << indent() << "public abstract global::System.Threading.Tasks.Task WriteAsync(TProtocol tProtocol, CancellationToken " << CANCELLATION_TOKEN_NAME << ");" << '\n'
        << indent() << "public readonly int Isset;" << '\n'
        << indent() << "public abstract object" << nullable_suffix() <<" Data { get; }" << '\n'
        << indent() << "protected " << normalize_name(tunion->get_name()) << "(int isset)" << '\n'
        << indent() << "{" << '\n';
    indent_up();
    out << indent() << "Isset = isset;" << '\n';
    indent_down();
    out << indent() << "}" << '\n' << '\n';

    const vector<t_field*>& fields = tunion->get_members();
    vector<t_field*>::const_iterator f_iter;

    out << indent() << "public override bool Equals(object" << nullable_suffix() << " that)" << '\n';
    scope_up(out);
    if( target_net_version >= 6) {
        out << indent() << "if (that is not " << tunion->get_name() << " other) return false;" << '\n';
    } else {
        out << indent() << "if (!(that is " << tunion->get_name() << " other)) return false;" << '\n';
    }
    out << indent() << "if (ReferenceEquals(this, other)) return true;" << '\n';
    out << '\n';
    out << indent() << "if(this.Isset != other.Isset) return false;" << '\n';
    out << '\n';
    if(target_net_version >= 6) {
        out << indent() << "return Isset switch" << '\n';
        scope_up(out);
        for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter)
        {
            bool needs_typecast = false;
            string suffix("");
            get_deep_copy_method_call((*f_iter)->get_type(), false, needs_typecast, suffix);
            out << indent() << (*f_iter)->get_key() << " => Equals(As_" << (*f_iter)->get_name() << ", other.As_" << (*f_iter)->get_name() << ")," << '\n';
        }
        out << indent() << "_ => true," << '\n';
        indent_down();
        out << indent() << "};" << '\n';
    } else {
        out << indent() << "switch (Isset)" << '\n';
        scope_up(out);
        for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter)
        {
            bool needs_typecast = false;
            string suffix("");
            get_deep_copy_method_call((*f_iter)->get_type(), false, needs_typecast, suffix);
            out << indent() << "case " << (*f_iter)->get_key() << ":" << '\n';
            indent_up();
            out << indent() << "return Equals(As_" << (*f_iter)->get_name() << ", other.As_" << (*f_iter)->get_name() << ");" << '\n';
            indent_down();
        }
        out << indent() << "default:" << '\n';
        indent_up();
        out << indent() << "return true;" << '\n';
        indent_down();
        scope_down(out);
    }
    scope_down(out);
    out << '\n';

    out << indent() << "public override int GetHashCode()" << '\n';
    out << indent() << "{" << '\n';
    indent_up();
    if(target_net_version >= 6) {
        out << indent() << "return Isset switch" << '\n';
        out << indent() << "{" << '\n';
        indent_up();
        for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter)
        {
            string null_coalesce(is_nullable_type((*f_iter)->get_type()) ? "?" : "");
            out << indent() << (*f_iter)->get_key() << " => As_" << (*f_iter)->get_name() << null_coalesce << ".GetHashCode()";
            if( null_coalesce.size() > 0) {
              out << " ?? 0";
            }
            out << "," << '\n';
        }
        out << indent() << "_ =>  (new ___undefined()).GetHashCode()" << '\n';
        indent_down();
        out << indent() << "};" << '\n';
    } else {
        out << indent() << "switch (Isset)" << '\n';
        out << indent() << "{" << '\n';
        indent_up();
        for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter)
        {
            string null_coalesce(is_nullable_type((*f_iter)->get_type()) ? "?" : "");
            out << indent() << "case " << (*f_iter)->get_key() << ":" << '\n';
            indent_up();
            out << indent() << "return As_" << (*f_iter)->get_name() << null_coalesce << ".GetHashCode()";
            if( null_coalesce.size() > 0) {
              out << " ?? 0";
            }
            out << ";" << '\n';
            indent_down();
        }
        out << indent() << "default:" << '\n';
        indent_up();
        out << indent() << "return (new ___undefined()).GetHashCode();" << '\n';
        indent_down();
        indent_down();
        out << indent() << "}" << '\n';
    }
    indent_down();
    out << indent() << "}" << '\n' << '\n';

    if( ! suppress_deepcopy) {
        out << indent() << "public " << tunion->get_name() << " " << DEEP_COPY_METHOD_NAME << "()" << '\n';
        out << indent() << "{" << '\n';
        indent_up();
        if(target_net_version >= 6) {
            out << indent() << "return Isset switch" << '\n';
            out << indent() << "{" << '\n';
            indent_up();
            for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter)
            {
                bool needs_typecast = false;
                string suffix("");
                string copy_op = get_deep_copy_method_call((*f_iter)->get_type(), false, needs_typecast, suffix);
                out << indent() << (*f_iter)->get_key() << " => new " << (*f_iter)->get_name() << "(As_" << (*f_iter)->get_name() << suffix << copy_op << ")," << '\n';
            }
            out << indent() << "_ => new ___undefined()" << '\n';
            indent_down();
            out << indent() << "};" << '\n';
        } else {
            out << indent() << "switch (Isset)" << '\n';
            out << indent() << "{" << '\n';
            indent_up();
            for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter)
            {
                bool needs_typecast = false;
                string suffix("");
                string copy_op = get_deep_copy_method_call((*f_iter)->get_type(), false, needs_typecast, suffix);
                out << indent() << "case " << (*f_iter)->get_key() << ":" << '\n';
                indent_up();
                out << indent() << "return new " << (*f_iter)->get_name() << "(As_" << (*f_iter)->get_name() << suffix << copy_op << ");" << '\n';
                indent_down();
            }
            out << indent() << "default:" << '\n';
            indent_up();
            out << indent() << "return new ___undefined();" << '\n';
            indent_down();
            indent_down();
            out << indent() << "}" << '\n';
        }
        indent_down();
        out << indent() << "}" << '\n' << '\n';
    }

    out << indent() << "public class ___undefined : " << tunion->get_name() << '\n';
    out << indent() << "{" << '\n';
    indent_up();

    out << indent() << "public override object" << nullable_suffix() <<" Data { get { return null; } }" << '\n'
        << indent() << "public ___undefined() : base(0) {}" << '\n' << '\n';

    if( ! suppress_deepcopy) {
        out << indent() << "public new ___undefined " << DEEP_COPY_METHOD_NAME << "()" << '\n';
        out << indent() << "{" << '\n';
        indent_up();
        out << indent() << "return new ___undefined();" << '\n';
        indent_down();
        out << indent() << "}" << '\n' << '\n';
    }

    t_struct undefined_struct(program_,"___undefined");
    generate_netstd_struct_equals(out, &undefined_struct);
    generate_netstd_struct_hashcode(out, &undefined_struct);

    out << indent() << "public override global::System.Threading.Tasks.Task WriteAsync(TProtocol oprot, CancellationToken " << CANCELLATION_TOKEN_NAME << ")" << '\n'
        << indent() << "{" << '\n';
    indent_up();
    out << indent() << "throw new TProtocolException( TProtocolException.INVALID_DATA, \"Cannot persist an union type which is not set.\");" << '\n';
    indent_down();
    out << indent() << "}" << '\n' << '\n';
    indent_down();
    out << indent() << "}" << '\n' << '\n';

    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter)
    {
        generate_netstd_union_class(out, tunion, (*f_iter));
    }

    generate_netstd_union_reader(out, tunion);

    indent_down();
    out << indent() << "}" << '\n' << '\n';

    end_netstd_namespace(out);
}