diff --git a/lang/csharp/src/apache/main/AvroDecimal.cs b/lang/csharp/src/apache/main/AvroDecimal.cs index ed748ae35f0..563056af021 100644 --- a/lang/csharp/src/apache/main/AvroDecimal.cs +++ b/lang/csharp/src/apache/main/AvroDecimal.cs @@ -917,7 +917,7 @@ TypeCode IConvertible.GetTypeCode() /// bool IConvertible.ToBoolean(IFormatProvider provider) { - return Convert.ToBoolean(this, provider); + return (bool)((IConvertible)this).ToType(typeof(bool), provider); } /// @@ -929,7 +929,7 @@ bool IConvertible.ToBoolean(IFormatProvider provider) /// byte IConvertible.ToByte(IFormatProvider provider) { - return Convert.ToByte(this, provider); + return (byte)((IConvertible)this).ToType(typeof(byte), provider); } /// @@ -967,7 +967,7 @@ DateTime IConvertible.ToDateTime(IFormatProvider provider) /// decimal IConvertible.ToDecimal(IFormatProvider provider) { - return Convert.ToDecimal(this, provider); + return (decimal)((IConvertible)this).ToType(typeof(decimal), provider); } /// @@ -979,7 +979,7 @@ decimal IConvertible.ToDecimal(IFormatProvider provider) /// double IConvertible.ToDouble(IFormatProvider provider) { - return Convert.ToDouble(this, provider); + return (double)((IConvertible)this).ToType(typeof(double), provider); } /// @@ -991,7 +991,7 @@ double IConvertible.ToDouble(IFormatProvider provider) /// short IConvertible.ToInt16(IFormatProvider provider) { - return Convert.ToInt16(this, provider); + return (short)((IConvertible)this).ToType(typeof(short), provider); } /// @@ -1003,7 +1003,7 @@ short IConvertible.ToInt16(IFormatProvider provider) /// int IConvertible.ToInt32(IFormatProvider provider) { - return Convert.ToInt32(this, provider); + return (int)((IConvertible)this).ToType(typeof(int), provider); } /// @@ -1015,7 +1015,7 @@ int IConvertible.ToInt32(IFormatProvider provider) /// long IConvertible.ToInt64(IFormatProvider provider) { - return Convert.ToInt64(this, provider); + return (long)((IConvertible)this).ToType(typeof(long), provider); } /// @@ -1027,7 +1027,7 @@ long IConvertible.ToInt64(IFormatProvider provider) /// sbyte IConvertible.ToSByte(IFormatProvider provider) { - return Convert.ToSByte(this, provider); + return (sbyte)((IConvertible)this).ToType(typeof(sbyte), provider); } /// @@ -1039,7 +1039,7 @@ sbyte IConvertible.ToSByte(IFormatProvider provider) /// float IConvertible.ToSingle(IFormatProvider provider) { - return Convert.ToSingle(this, provider); + return (float)((IConvertible)this).ToType(typeof(float), provider); } /// @@ -1051,7 +1051,7 @@ float IConvertible.ToSingle(IFormatProvider provider) /// string IConvertible.ToString(IFormatProvider provider) { - return Convert.ToString(this, provider); + return ToString(); } /// @@ -1063,7 +1063,7 @@ string IConvertible.ToString(IFormatProvider provider) /// ushort IConvertible.ToUInt16(IFormatProvider provider) { - return Convert.ToUInt16(this, provider); + return (ushort)((IConvertible)this).ToType(typeof(ushort), provider); } /// @@ -1075,7 +1075,7 @@ ushort IConvertible.ToUInt16(IFormatProvider provider) /// uint IConvertible.ToUInt32(IFormatProvider provider) { - return Convert.ToUInt32(this, provider); + return (uint)((IConvertible)this).ToType(typeof(uint), provider); } /// @@ -1087,7 +1087,7 @@ uint IConvertible.ToUInt32(IFormatProvider provider) /// ulong IConvertible.ToUInt64(IFormatProvider provider) { - return Convert.ToUInt64(this, provider); + return (ulong)((IConvertible)this).ToType(typeof(ulong), provider); } /// diff --git a/lang/csharp/src/apache/test/AvroDecimalTest.cs b/lang/csharp/src/apache/test/AvroDecimalTest.cs index c6d0d3a807e..75b39add41f 100644 --- a/lang/csharp/src/apache/test/AvroDecimalTest.cs +++ b/lang/csharp/src/apache/test/AvroDecimalTest.cs @@ -16,6 +16,7 @@ * limitations under the License. */ +using System; using System.Globalization; using NUnit.Framework; @@ -91,5 +92,28 @@ public int TestAvroDecimalCompareTo(string left, string right) return leftAvroDecimal.CompareTo(rightAvroDecimal); } + + // AVRO-3569: the IConvertible conversions previously called + // Convert.ToXxx(this, provider), which recurses back into the same + // IConvertible method and overflows the stack. Verify they now return + // the converted value instead of crashing. + [Test] + public void TestAvroDecimalIConvertibleDoesNotRecurse() + { + var d = new AvroDecimal(42); + Assert.AreEqual((byte)42, Convert.ToByte(d)); + Assert.AreEqual((sbyte)42, Convert.ToSByte(d)); + Assert.AreEqual((short)42, Convert.ToInt16(d)); + Assert.AreEqual(42, Convert.ToInt32(d)); + Assert.AreEqual(42L, Convert.ToInt64(d)); + Assert.AreEqual((ushort)42, Convert.ToUInt16(d)); + Assert.AreEqual(42u, Convert.ToUInt32(d)); + Assert.AreEqual(42ul, Convert.ToUInt64(d)); + Assert.AreEqual(42d, Convert.ToDouble(d)); + Assert.AreEqual(42f, Convert.ToSingle(d)); + Assert.AreEqual(42m, Convert.ToDecimal(d)); + Assert.AreEqual(true, Convert.ToBoolean(d)); + Assert.AreEqual("42", Convert.ToString(d, CultureInfo.InvariantCulture)); + } } }