summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compiler/cpp/src/generate/t_csharp_generator.cc100
-rw-r--r--lib/csharp/Makefile.am1
-rw-r--r--lib/csharp/src/Collections/TCollections.cs94
-rw-r--r--lib/csharp/src/Thrift.WP7.csproj1
-rw-r--r--lib/csharp/src/Thrift.csproj5
5 files changed, 199 insertions, 2 deletions
diff --git a/compiler/cpp/src/generate/t_csharp_generator.cc b/compiler/cpp/src/generate/t_csharp_generator.cc
index b9e0b7560..f0972cf1e 100644
--- a/compiler/cpp/src/generate/t_csharp_generator.cc
+++ b/compiler/cpp/src/generate/t_csharp_generator.cc
@@ -66,6 +66,9 @@ class t_csharp_generator : public t_oop_generator
iter = parsed_options.find("nullable");
nullable_ = (iter != parsed_options.end());
+ iter = parsed_options.find("hashcode");
+ hashcode_ = (iter != parsed_options.end());
+
iter = parsed_options.find("union");
union_ = (iter != parsed_options.end());
@@ -111,6 +114,8 @@ class t_csharp_generator : public t_oop_generator
void generate_csharp_struct_result_writer(std::ofstream& out, t_struct* tstruct);
void generate_csharp_struct_writer(std::ofstream& out, t_struct* tstruct);
void generate_csharp_struct_tostring(std::ofstream& out, t_struct* tstruct);
+ void generate_csharp_struct_equals(std::ofstream& out, t_struct* tstruct);
+ void generate_csharp_struct_hashcode(std::ofstream& out, t_struct* tstruct);
void generate_csharp_union_reader(std::ofstream& out, t_struct* tunion);
void generate_function_helpers(t_function* tfunction);
@@ -183,6 +188,7 @@ class t_csharp_generator : public t_oop_generator
bool async_ctp_;
bool nullable_;
bool union_;
+ bool hashcode_;
bool serialize_;
bool wcf_;
std::string wcf_namespace_;
@@ -576,6 +582,7 @@ void t_csharp_generator::generate_csharp_struct_definition(ofstream &out, t_stru
// We always want a default, no argument constructor for Reading
indent(out) << "public " << tstruct->get_name() << "() {" << endl;
indent_up();
+
for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
t_type* t = (*m_iter)->get_type();
while (t->is_typedef()) {
@@ -626,6 +633,10 @@ void t_csharp_generator::generate_csharp_struct_definition(ofstream &out, t_stru
} else {
generate_csharp_struct_writer(out, tstruct);
}
+ if (hashcode_) {
+ generate_csharp_struct_equals(out, tstruct);
+ generate_csharp_struct_hashcode(out, tstruct);
+ }
generate_csharp_struct_tostring(out, tstruct);
scope_down(out);
out << endl;
@@ -1034,6 +1045,94 @@ void t_csharp_generator::generate_csharp_union_class(std::ofstream& out, t_struc
indent(out) << "}" << endl << endl;
}
+
+void t_csharp_generator::generate_csharp_struct_equals(ofstream& out, t_struct* tstruct) {
+ indent(out) << "public override bool Equals(object that) {" << endl;
+ indent_up();
+
+ indent(out) << "var other = that as " << type_name(tstruct) << ";" << endl;
+ indent(out) << "if (other == null) return false;" << endl;
+ indent(out) << "if (ReferenceEquals(this, other)) return true;" << endl;
+
+ const vector<t_field*>& fields = tstruct->get_members();
+ vector<t_field*>::const_iterator f_iter;
+
+ bool first = true;
+
+ for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+ if (first) {
+ first = false;
+ indent(out) << "return ";
+ indent_up();
+ } else {
+ out << endl;
+ indent(out) << "&& ";
+ }
+ if (!field_is_required((*f_iter)) && !(nullable_ && !field_has_default((*f_iter)))) {
+ out << "((__isset." << (*f_iter)->get_name() << " == other.__isset." << (*f_iter)->get_name() << ") && ((!__isset." << (*f_iter)->get_name() << ") || (";
+ }
+ t_type* ttype = (*f_iter)->get_type();
+ if (ttype->is_container()) {
+ out << "TCollections.Equals(" << prop_name((*f_iter)) << ", other." << prop_name((*f_iter)) << ")";
+ } else {
+ out << prop_name((*f_iter)) << ".Equals(other." << prop_name((*f_iter)) << ")";
+ }
+ if (!field_is_required((*f_iter)) && !(nullable_ && !field_has_default((*f_iter)))) {
+ out << ")))";
+ }
+ }
+ if (first) {
+ indent(out) << "return true;" << endl;
+ } else {
+ out << ";" << endl;
+ indent_down();
+ }
+
+ indent_down();
+ indent(out) << "}" << endl << endl;
+}
+
+void t_csharp_generator::generate_csharp_struct_hashcode(ofstream& out, t_struct* tstruct) {
+ indent(out) << "public override int GetHashCode() {" << endl;
+ indent_up();
+
+ indent(out) << "int hashcode = 0;" << endl;
+ indent(out) << "unchecked {" << endl;
+ indent_up();
+
+ const vector<t_field*>& fields = tstruct->get_members();
+ vector<t_field*>::const_iterator f_iter;
+
+ for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+ t_type* ttype = (*f_iter)->get_type();
+ indent(out) << "hashcode = (hashcode * 397) ^ ";
+ if (field_is_required((*f_iter))) {
+ out << "(";
+ } else if ( nullable_) {
+ out << "(" << prop_name((*f_iter)) << " == null ? 0 : ";
+ }else {
+ out << "(!__isset." << (*f_iter)->get_name() << " ? 0 : ";
+ }
+ if (ttype->is_container()) {
+ out << "(TCollections.GetHashCode("
+ << prop_name((*f_iter))
+ << "))";
+ } else {
+ out << "("
+ << prop_name((*f_iter))
+ << ".GetHashCode())";
+ }
+ out << ");" << endl;
+ }
+
+ indent_down();
+ indent(out) << "}" << endl;
+ indent(out) << "return hashcode;" << endl;
+
+ indent_down();
+ indent(out) << "}" << endl << endl;
+}
+
void t_csharp_generator::generate_service(t_service* tservice) {
string f_service_name = namespace_dir_ + "/" + service_name_ + ".cs";
f_service_.open(f_service_name.c_str());
@@ -2394,6 +2493,7 @@ THRIFT_REGISTER_GENERATOR(csharp, "C#",
" wcf: Adds bindings for WCF to generated classes.\n"
" serial: Add serialization support to generated classes.\n"
" nullable: Use nullable types for properties.\n"
+" hashcode: Generate a hashcode and equals implementation for classes.\n"
" union: Use new union typing, which includes a static read function for union types.\n"
)
diff --git a/lib/csharp/Makefile.am b/lib/csharp/Makefile.am
index 9b07f4fbd..f13f90a0f 100644
--- a/lib/csharp/Makefile.am
+++ b/lib/csharp/Makefile.am
@@ -19,6 +19,7 @@
THRIFTCODE= \
src/Collections/THashSet.cs \
+ src/Collections/TCollections.cs \
src/Properties/AssemblyInfo.cs \
src/Protocol/TAbstractBase.cs \
src/Protocol/TBase.cs \
diff --git a/lib/csharp/src/Collections/TCollections.cs b/lib/csharp/src/Collections/TCollections.cs
new file mode 100644
index 000000000..23fd8da3e
--- /dev/null
+++ b/lib/csharp/src/Collections/TCollections.cs
@@ -0,0 +1,94 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+using System;
+using System.Collections;
+
+namespace Thrift.Collections
+{
+ public class TCollections
+ {
+ /// <summary>
+ /// This will return true if the two collections are value-wise the same.
+ /// If the collection contains a collection, the collections will be compared using this method.
+ /// </summary>
+ public static bool Equals (IEnumerable first, IEnumerable second)
+ {
+ if (first == null && second == null)
+ {
+ return true;
+ }
+ if (first == null || second == null)
+ {
+ return false;
+ }
+ IEnumerator fiter = first.GetEnumerator ();
+ IEnumerator siter = second.GetEnumerator ();
+
+ bool fnext = fiter.MoveNext ();
+ bool snext = siter.MoveNext ();
+ while (fnext && snext)
+ {
+ IEnumerable fenum = fiter.Current as IEnumerable;
+ IEnumerable senum = siter.Current as IEnumerable;
+ if (fenum != null && senum != null)
+ {
+ if (!Equals(fenum, senum))
+ {
+ return false;
+ }
+ }
+ else if (fenum == null ^ senum == null)
+ {
+ return false;
+ }
+ else if (!Equals(fiter.Current, siter.Current))
+ {
+ return false;
+ }
+ fnext = fiter.MoveNext();
+ snext = siter.MoveNext();
+ }
+
+ return fnext == snext;
+ }
+
+ /// <summary>
+ /// This returns a hashcode based on the value of the enumerable.
+ /// </summary>
+ public static int GetHashCode (IEnumerable enumerable)
+ {
+ if (enumerable == null)
+ {
+ return 0;
+ }
+
+ int hashcode = 0;
+ foreach (Object obj in enumerable)
+ {
+ IEnumerable enum2 = obj as IEnumerable;
+ int objHash = enum2 == null ? obj.GetHashCode () : GetHashCode (enum2);
+ unchecked
+ {
+ hashcode = (hashcode * 397) ^ (objHash);
+ }
+ }
+ return hashcode;
+ }
+ }
+} \ No newline at end of file
diff --git a/lib/csharp/src/Thrift.WP7.csproj b/lib/csharp/src/Thrift.WP7.csproj
index be38bc83e..3d5b027b0 100644
--- a/lib/csharp/src/Thrift.WP7.csproj
+++ b/lib/csharp/src/Thrift.WP7.csproj
@@ -70,6 +70,7 @@
<Reference Include="System.Net" />
</ItemGroup>
<ItemGroup>
+ <Compile Include="Collections\TCollections.cs" />
<Compile Include="Collections\THashSet.cs" />
<Compile Include="Properties\AssemblyInfo.WP7.cs" />
<Compile Include="Protocol\TBase.cs" />
diff --git a/lib/csharp/src/Thrift.csproj b/lib/csharp/src/Thrift.csproj
index 0263d7284..0722c18bc 100644
--- a/lib/csharp/src/Thrift.csproj
+++ b/lib/csharp/src/Thrift.csproj
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
@@ -77,6 +77,7 @@
<Reference Include="System.Web" />
</ItemGroup>
<ItemGroup>
+ <Compile Include="Collections\TCollections.cs" />
<Compile Include="Collections\THashSet.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Protocol\TAbstractBase.cs" />
@@ -137,4 +138,4 @@
<ProjectExtensions>
<VisualStudio AllowExistingFolder="true" />
</ProjectExtensions>
-</Project> \ No newline at end of file
+</Project>