From f6d63d9238e43b0fa2629eaff351b5bdf957466c Mon Sep 17 00:00:00 2001 From: Brandon Williams Date: Mon, 7 Oct 2024 21:00:23 -0700 Subject: [PATCH 1/6] Add a test --- .../FbZonedDateTimeTypeTests.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/FirebirdSql.Data.FirebirdClient.Tests/FbZonedDateTimeTypeTests.cs b/src/FirebirdSql.Data.FirebirdClient.Tests/FbZonedDateTimeTypeTests.cs index ca94f33e..a25fd744 100644 --- a/src/FirebirdSql.Data.FirebirdClient.Tests/FbZonedDateTimeTypeTests.cs +++ b/src/FirebirdSql.Data.FirebirdClient.Tests/FbZonedDateTimeTypeTests.cs @@ -47,6 +47,14 @@ public void EqualityFalse(FbZonedDateTime expected, FbZonedDateTime actual) Assert.AreNotEqual(expected, actual); } + [Test] + public void ConvertToDateTimeShouldNotThrow() + { + FbZonedDateTime fbZonedDateTime = new(new DateTime(2020, 12, 4, 10, 38, 0, DateTimeKind.Utc), "UTC"); + + Assert.DoesNotThrow(() => Convert.ChangeType(fbZonedDateTime, typeof(DateTime))); + } + public void DateTimeShouldBeUtc() { Assert.Throws(() => From ef20de8641749e5ee1289aff4f3a7fd707974b36 Mon Sep 17 00:00:00 2001 From: Brandon Williams Date: Mon, 7 Oct 2024 21:02:37 -0700 Subject: [PATCH 2/6] Implement IConvertible for FbZonedDateTime --- .../Types/FbZonedDateTime.cs | 40 +++++++++++++++++-- 1 file changed, 37 insertions(+), 3 deletions(-) diff --git a/src/FirebirdSql.Data.FirebirdClient/Types/FbZonedDateTime.cs b/src/FirebirdSql.Data.FirebirdClient/Types/FbZonedDateTime.cs index b2eff99b..88b6f37f 100644 --- a/src/FirebirdSql.Data.FirebirdClient/Types/FbZonedDateTime.cs +++ b/src/FirebirdSql.Data.FirebirdClient/Types/FbZonedDateTime.cs @@ -21,7 +21,7 @@ namespace FirebirdSql.Data.Types; [StructLayout(LayoutKind.Auto)] -public readonly struct FbZonedDateTime : IEquatable +public readonly struct FbZonedDateTime : IConvertible, IEquatable { public DateTime DateTime { get; } public string TimeZone { get; } @@ -72,8 +72,42 @@ public override int GetHashCode() } } - public bool Equals(FbZonedDateTime other) => DateTime.Equals(other.DateTime) && TimeZone.Equals(other.TimeZone, StringComparison.OrdinalIgnoreCase); - + public bool Equals(FbZonedDateTime other) => DateTime.Equals(other.DateTime) && TimeZone.Equals(other.TimeZone, StringComparison.OrdinalIgnoreCase); + + public TypeCode GetTypeCode() => TypeCode.Object; + + public bool ToBoolean(IFormatProvider provider) => throw new InvalidCastException(nameof(Boolean)); + + public byte ToByte(IFormatProvider provider) => throw new InvalidCastException(nameof(Byte)); + + public char ToChar(IFormatProvider provider) => throw new InvalidCastException(nameof(Char)); + + public DateTime ToDateTime(IFormatProvider provider) => DateTime; + + public decimal ToDecimal(IFormatProvider provider) => throw new InvalidCastException(nameof(Decimal)); + + public double ToDouble(IFormatProvider provider) => throw new InvalidCastException(nameof(Double)); + + public short ToInt16(IFormatProvider provider) => throw new InvalidCastException(nameof(Int16)); + + public int ToInt32(IFormatProvider provider) => throw new InvalidCastException(nameof(Int32)); + + public long ToInt64(IFormatProvider provider) => throw new InvalidCastException(nameof(Int64)); + + public sbyte ToSByte(IFormatProvider provider) => throw new InvalidCastException(nameof(SByte)); + + public float ToSingle(IFormatProvider provider) => throw new InvalidCastException(nameof(Single)); + + public string ToString(IFormatProvider provider) => throw new InvalidCastException(nameof(String)); + + public object ToType(Type conversionType, IFormatProvider provider) => throw new InvalidCastException(nameof(conversionType)); + + public ushort ToUInt16(IFormatProvider provider) => throw new InvalidCastException(nameof(UInt16)); + + public uint ToUInt32(IFormatProvider provider) => throw new InvalidCastException(nameof(UInt32)); + + public ulong ToUInt64(IFormatProvider provider) => throw new InvalidCastException(nameof(UInt64)); + public static bool operator ==(FbZonedDateTime lhs, FbZonedDateTime rhs) => lhs.Equals(rhs); public static bool operator !=(FbZonedDateTime lhs, FbZonedDateTime rhs) => lhs.Equals(rhs); From 573d80bf80ec513e8f789c05f6b3d20d940c9b2f Mon Sep 17 00:00:00 2001 From: Brandon Williams Date: Mon, 7 Oct 2024 22:19:03 -0700 Subject: [PATCH 3/6] Add implementation for IConvertible interface method ToType --- .../Types/FbZonedDateTime.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/FirebirdSql.Data.FirebirdClient/Types/FbZonedDateTime.cs b/src/FirebirdSql.Data.FirebirdClient/Types/FbZonedDateTime.cs index 88b6f37f..ebd8349a 100644 --- a/src/FirebirdSql.Data.FirebirdClient/Types/FbZonedDateTime.cs +++ b/src/FirebirdSql.Data.FirebirdClient/Types/FbZonedDateTime.cs @@ -100,7 +100,15 @@ public override int GetHashCode() public string ToString(IFormatProvider provider) => throw new InvalidCastException(nameof(String)); - public object ToType(Type conversionType, IFormatProvider provider) => throw new InvalidCastException(nameof(conversionType)); + public object ToType(Type conversionType, IFormatProvider provider) + { + if (ReferenceEquals(conversionType, typeof(FbZonedDateTime))) + { + return this; + } + + throw new InvalidCastException(conversionType?.FullName); + } public ushort ToUInt16(IFormatProvider provider) => throw new InvalidCastException(nameof(UInt16)); From 541c9734febcf6434bb0b2b3103f130d696de648 Mon Sep 17 00:00:00 2001 From: Brandon Williams Date: Mon, 7 Oct 2024 23:27:42 -0700 Subject: [PATCH 4/6] Implement members explicitly --- .../Types/FbZonedDateTime.cs | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/FirebirdSql.Data.FirebirdClient/Types/FbZonedDateTime.cs b/src/FirebirdSql.Data.FirebirdClient/Types/FbZonedDateTime.cs index ebd8349a..33656b9a 100644 --- a/src/FirebirdSql.Data.FirebirdClient/Types/FbZonedDateTime.cs +++ b/src/FirebirdSql.Data.FirebirdClient/Types/FbZonedDateTime.cs @@ -74,33 +74,33 @@ public override int GetHashCode() public bool Equals(FbZonedDateTime other) => DateTime.Equals(other.DateTime) && TimeZone.Equals(other.TimeZone, StringComparison.OrdinalIgnoreCase); - public TypeCode GetTypeCode() => TypeCode.Object; + TypeCode IConvertible.GetTypeCode() => TypeCode.Object; - public bool ToBoolean(IFormatProvider provider) => throw new InvalidCastException(nameof(Boolean)); + bool IConvertible.ToBoolean(IFormatProvider provider) => throw new InvalidCastException(nameof(Boolean)); - public byte ToByte(IFormatProvider provider) => throw new InvalidCastException(nameof(Byte)); + byte IConvertible. ToByte(IFormatProvider provider) => throw new InvalidCastException(nameof(Byte)); - public char ToChar(IFormatProvider provider) => throw new InvalidCastException(nameof(Char)); + char IConvertible. ToChar(IFormatProvider provider) => throw new InvalidCastException(nameof(Char)); - public DateTime ToDateTime(IFormatProvider provider) => DateTime; + DateTime IConvertible. ToDateTime(IFormatProvider provider) => DateTime; - public decimal ToDecimal(IFormatProvider provider) => throw new InvalidCastException(nameof(Decimal)); + decimal IConvertible. ToDecimal(IFormatProvider provider) => throw new InvalidCastException(nameof(Decimal)); - public double ToDouble(IFormatProvider provider) => throw new InvalidCastException(nameof(Double)); + double IConvertible. ToDouble(IFormatProvider provider) => throw new InvalidCastException(nameof(Double)); - public short ToInt16(IFormatProvider provider) => throw new InvalidCastException(nameof(Int16)); + short IConvertible. ToInt16(IFormatProvider provider) => throw new InvalidCastException(nameof(Int16)); - public int ToInt32(IFormatProvider provider) => throw new InvalidCastException(nameof(Int32)); + int IConvertible. ToInt32(IFormatProvider provider) => throw new InvalidCastException(nameof(Int32)); - public long ToInt64(IFormatProvider provider) => throw new InvalidCastException(nameof(Int64)); + long IConvertible. ToInt64(IFormatProvider provider) => throw new InvalidCastException(nameof(Int64)); - public sbyte ToSByte(IFormatProvider provider) => throw new InvalidCastException(nameof(SByte)); + sbyte IConvertible. ToSByte(IFormatProvider provider) => throw new InvalidCastException(nameof(SByte)); - public float ToSingle(IFormatProvider provider) => throw new InvalidCastException(nameof(Single)); + float IConvertible. ToSingle(IFormatProvider provider) => throw new InvalidCastException(nameof(Single)); - public string ToString(IFormatProvider provider) => throw new InvalidCastException(nameof(String)); + string IConvertible.ToString(IFormatProvider provider) => ToString(); - public object ToType(Type conversionType, IFormatProvider provider) + object IConvertible.ToType(Type conversionType, IFormatProvider provider) { if (ReferenceEquals(conversionType, typeof(FbZonedDateTime))) { @@ -110,11 +110,11 @@ public object ToType(Type conversionType, IFormatProvider provider) throw new InvalidCastException(conversionType?.FullName); } - public ushort ToUInt16(IFormatProvider provider) => throw new InvalidCastException(nameof(UInt16)); + ushort IConvertible.ToUInt16(IFormatProvider provider) => throw new InvalidCastException(nameof(UInt16)); - public uint ToUInt32(IFormatProvider provider) => throw new InvalidCastException(nameof(UInt32)); + uint IConvertible.ToUInt32(IFormatProvider provider) => throw new InvalidCastException(nameof(UInt32)); - public ulong ToUInt64(IFormatProvider provider) => throw new InvalidCastException(nameof(UInt64)); + ulong IConvertible.ToUInt64(IFormatProvider provider) => throw new InvalidCastException(nameof(UInt64)); public static bool operator ==(FbZonedDateTime lhs, FbZonedDateTime rhs) => lhs.Equals(rhs); From 87890e8a1792eee7d1fab0cfbd7837ec1507c18f Mon Sep 17 00:00:00 2001 From: Brandon Williams Date: Mon, 7 Oct 2024 23:38:26 -0700 Subject: [PATCH 5/6] Fix spacing --- .../Types/FbZonedDateTime.cs | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/FirebirdSql.Data.FirebirdClient/Types/FbZonedDateTime.cs b/src/FirebirdSql.Data.FirebirdClient/Types/FbZonedDateTime.cs index 33656b9a..24ae3bc3 100644 --- a/src/FirebirdSql.Data.FirebirdClient/Types/FbZonedDateTime.cs +++ b/src/FirebirdSql.Data.FirebirdClient/Types/FbZonedDateTime.cs @@ -78,25 +78,25 @@ public override int GetHashCode() bool IConvertible.ToBoolean(IFormatProvider provider) => throw new InvalidCastException(nameof(Boolean)); - byte IConvertible. ToByte(IFormatProvider provider) => throw new InvalidCastException(nameof(Byte)); + byte IConvertible.ToByte(IFormatProvider provider) => throw new InvalidCastException(nameof(Byte)); - char IConvertible. ToChar(IFormatProvider provider) => throw new InvalidCastException(nameof(Char)); + char IConvertible.ToChar(IFormatProvider provider) => throw new InvalidCastException(nameof(Char)); - DateTime IConvertible. ToDateTime(IFormatProvider provider) => DateTime; + DateTime IConvertible.ToDateTime(IFormatProvider provider) => DateTime; - decimal IConvertible. ToDecimal(IFormatProvider provider) => throw new InvalidCastException(nameof(Decimal)); + decimal IConvertible.ToDecimal(IFormatProvider provider) => throw new InvalidCastException(nameof(Decimal)); - double IConvertible. ToDouble(IFormatProvider provider) => throw new InvalidCastException(nameof(Double)); + double IConvertible.ToDouble(IFormatProvider provider) => throw new InvalidCastException(nameof(Double)); - short IConvertible. ToInt16(IFormatProvider provider) => throw new InvalidCastException(nameof(Int16)); + short IConvertible.ToInt16(IFormatProvider provider) => throw new InvalidCastException(nameof(Int16)); - int IConvertible. ToInt32(IFormatProvider provider) => throw new InvalidCastException(nameof(Int32)); + int IConvertible.ToInt32(IFormatProvider provider) => throw new InvalidCastException(nameof(Int32)); - long IConvertible. ToInt64(IFormatProvider provider) => throw new InvalidCastException(nameof(Int64)); + long IConvertible.ToInt64(IFormatProvider provider) => throw new InvalidCastException(nameof(Int64)); - sbyte IConvertible. ToSByte(IFormatProvider provider) => throw new InvalidCastException(nameof(SByte)); + sbyte IConvertible.ToSByte(IFormatProvider provider) => throw new InvalidCastException(nameof(SByte)); - float IConvertible. ToSingle(IFormatProvider provider) => throw new InvalidCastException(nameof(Single)); + float IConvertible.ToSingle(IFormatProvider provider) => throw new InvalidCastException(nameof(Single)); string IConvertible.ToString(IFormatProvider provider) => ToString(); From bdd3ee03784bf3469cb0bbaa502cc7e421851083 Mon Sep 17 00:00:00 2001 From: Brandon Williams Date: Tue, 8 Oct 2024 18:48:44 -0700 Subject: [PATCH 6/6] Apply requested changes from review --- .../FbZonedDateTimeTypeTests.cs | 2 +- .../Types/FbZonedDateTime.cs | 23 +++++++------------ 2 files changed, 9 insertions(+), 16 deletions(-) diff --git a/src/FirebirdSql.Data.FirebirdClient.Tests/FbZonedDateTimeTypeTests.cs b/src/FirebirdSql.Data.FirebirdClient.Tests/FbZonedDateTimeTypeTests.cs index a25fd744..b69dc704 100644 --- a/src/FirebirdSql.Data.FirebirdClient.Tests/FbZonedDateTimeTypeTests.cs +++ b/src/FirebirdSql.Data.FirebirdClient.Tests/FbZonedDateTimeTypeTests.cs @@ -50,7 +50,7 @@ public void EqualityFalse(FbZonedDateTime expected, FbZonedDateTime actual) [Test] public void ConvertToDateTimeShouldNotThrow() { - FbZonedDateTime fbZonedDateTime = new(new DateTime(2020, 12, 4, 10, 38, 0, DateTimeKind.Utc), "UTC"); + var fbZonedDateTime = new FbZonedDateTime(new DateTime(2020, 12, 4, 10, 38, 0, DateTimeKind.Utc), "UTC"); Assert.DoesNotThrow(() => Convert.ChangeType(fbZonedDateTime, typeof(DateTime))); } diff --git a/src/FirebirdSql.Data.FirebirdClient/Types/FbZonedDateTime.cs b/src/FirebirdSql.Data.FirebirdClient/Types/FbZonedDateTime.cs index 24ae3bc3..78ad2c5a 100644 --- a/src/FirebirdSql.Data.FirebirdClient/Types/FbZonedDateTime.cs +++ b/src/FirebirdSql.Data.FirebirdClient/Types/FbZonedDateTime.cs @@ -21,7 +21,7 @@ namespace FirebirdSql.Data.Types; [StructLayout(LayoutKind.Auto)] -public readonly struct FbZonedDateTime : IConvertible, IEquatable +public readonly struct FbZonedDateTime : IEquatable, IConvertible { public DateTime DateTime { get; } public string TimeZone { get; } @@ -76,14 +76,19 @@ public override int GetHashCode() TypeCode IConvertible.GetTypeCode() => TypeCode.Object; + DateTime IConvertible.ToDateTime(IFormatProvider provider) => DateTime; + + string IConvertible.ToString(IFormatProvider provider) => ToString(); + + object IConvertible.ToType(Type conversionType, IFormatProvider provider) + => ReferenceEquals(conversionType, typeof(FbZonedDateTime)) ? this : throw new InvalidCastException(conversionType?.FullName); + bool IConvertible.ToBoolean(IFormatProvider provider) => throw new InvalidCastException(nameof(Boolean)); byte IConvertible.ToByte(IFormatProvider provider) => throw new InvalidCastException(nameof(Byte)); char IConvertible.ToChar(IFormatProvider provider) => throw new InvalidCastException(nameof(Char)); - DateTime IConvertible.ToDateTime(IFormatProvider provider) => DateTime; - decimal IConvertible.ToDecimal(IFormatProvider provider) => throw new InvalidCastException(nameof(Decimal)); double IConvertible.ToDouble(IFormatProvider provider) => throw new InvalidCastException(nameof(Double)); @@ -98,18 +103,6 @@ public override int GetHashCode() float IConvertible.ToSingle(IFormatProvider provider) => throw new InvalidCastException(nameof(Single)); - string IConvertible.ToString(IFormatProvider provider) => ToString(); - - object IConvertible.ToType(Type conversionType, IFormatProvider provider) - { - if (ReferenceEquals(conversionType, typeof(FbZonedDateTime))) - { - return this; - } - - throw new InvalidCastException(conversionType?.FullName); - } - ushort IConvertible.ToUInt16(IFormatProvider provider) => throw new InvalidCastException(nameof(UInt16)); uint IConvertible.ToUInt32(IFormatProvider provider) => throw new InvalidCastException(nameof(UInt32));