diff --git a/docs/fundamentals/code-analysis/quality-rules/ca1036.md b/docs/fundamentals/code-analysis/quality-rules/ca1036.md index 5114299764df8..b3c04be4de301 100644 --- a/docs/fundamentals/code-analysis/quality-rules/ca1036.md +++ b/docs/fundamentals/code-analysis/quality-rules/ca1036.md @@ -10,6 +10,9 @@ helpviewer_keywords: - CA1036 author: gewarren ms.author: gewarren +dev_langs: +- CSharp +- VB --- # CA1036: Override methods on comparable types @@ -35,23 +38,42 @@ Types that define a custom sort order implement the in To fix a violation of this rule, override . If your programming language supports operator overloading, supply the following operators: -- op_Equality -- op_Inequality -- op_LessThan -- op_GreaterThan - -In C#, the tokens that are used to represent these operators are as follows: +- `op_Equality` +- `op_Inequality` +- `op_LessThan` +- `op_GreaterThan` ```csharp -== -!= -< -> +// In C#, implement these operators. +public static bool operator ==(SampleClass? one, SampleClass? other) { } +public static bool operator !=(SampleClass? one, SampleClass? other) { } +public static bool operator <(SampleClass? one, SampleClass? other) { } +public static bool operator >(SampleClass? one, SampleClass? other) { } +``` + +```vb +' In Visual Basic, implement these operators. + +Public Shared Operator =(one As SampleClass, other As SampleClass) As Boolean + ... +End Operator + +Public Shared Operator <>(one As SampleClass, other As SampleClass) As Boolean + ... +End Operator + +Public Shared Operator <(one As SampleClass, other As SampleClass) As Boolean + ... +End Operator + +Public Shared Operator >(one As SampleClass, other As SampleClass) As Boolean + ... +End Operator ``` ## When to suppress warnings -It is safe to suppress a warning from rule CA1036 when the violation is caused by missing operators and your programming language does not support operator overloading, as is the case with Visual Basic. If you determine that implementing the operators does not make sense in your app context, it's also safe to suppress a warning from this rule when it fires on equality operators other than op_Equality. However, you should always override op_Equality and the == operator if you override . +It's safe to suppress a warning from rule CA1036 when the violation is caused by missing operators and your programming language does not support operator overloading. If you determine that implementing the operators does not make sense in your app context, it's also safe to suppress a warning from this rule when it fires on equality operators other than `op_Equality`. However, you should always override `op_Equality` and the `==` operator if you override . ## Suppress a warning @@ -87,10 +109,12 @@ You can configure this option for just this rule, for all rules it applies to, o The following code contains a type that correctly implements . Code comments identify the methods that satisfy various rules that are related to and the interface. :::code language="csharp" source="snippets/csharp/all-rules/ca1036.cs" id="snippet1"::: +:::code language="vb" source="snippets/vb/all-rules/ca1036.vb" id="snippet1"::: The following application code tests the behavior of the implementation that was shown earlier. :::code language="csharp" source="snippets/csharp/all-rules/ca1036.cs" id="snippet2"::: +:::code language="vb" source="snippets/vb/all-rules/ca1036.vb" id="snippet2"::: ## See also diff --git a/docs/fundamentals/code-analysis/quality-rules/snippets/csharp/all-rules/Program.cs b/docs/fundamentals/code-analysis/quality-rules/snippets/csharp/all-rules/Program.cs new file mode 100644 index 0000000000000..e221ad0970131 --- /dev/null +++ b/docs/fundamentals/code-analysis/quality-rules/snippets/csharp/all-rules/Program.cs @@ -0,0 +1 @@ +TestCompare.Main1036("A", "B"); diff --git a/docs/fundamentals/code-analysis/quality-rules/snippets/csharp/all-rules/ca1036.cs b/docs/fundamentals/code-analysis/quality-rules/snippets/csharp/all-rules/ca1036.cs index f00e506b471ce..a7443668d5edc 100644 --- a/docs/fundamentals/code-analysis/quality-rules/snippets/csharp/all-rules/ca1036.cs +++ b/docs/fundamentals/code-analysis/quality-rules/snippets/csharp/all-rules/ca1036.cs @@ -1,143 +1,134 @@ using System; using System.Globalization; -namespace ca1036 +// +// Valid ratings are between A and C. +// A is the highest rating; it is greater than any other valid rating. +// C is the lowest rating; it is less than any other valid rating. + +public class RatingInformation : IComparable, IComparable { - // - // Valid ratings are between A and C. - // A is the highest rating; it is greater than any other valid rating. - // C is the lowest rating; it is less than any other valid rating. + public string Rating { get; private set; } - public class RatingInformation : IComparable, IComparable + public RatingInformation(string rating) { - public string Rating - { - get; - private set; - } + ArgumentNullException.ThrowIfNull(rating); - public RatingInformation(string rating) + string v = rating.ToUpper(CultureInfo.InvariantCulture); + if (v.Length != 1 || + string.Compare(v, "C", StringComparison.Ordinal) > 0 || + string.Compare(v, "A", StringComparison.Ordinal) < 0) { - if (rating == null) - { - throw new ArgumentNullException("rating"); - } - - string v = rating.ToUpper(CultureInfo.InvariantCulture); - if (v.Length != 1 || string.Compare(v, "C", StringComparison.Ordinal) > 0 || string.Compare(v, "A", StringComparison.Ordinal) < 0) - { - throw new ArgumentException("Invalid rating value was specified.", "rating"); - } - - Rating = v; + throw new ArgumentException("Invalid rating value was specified.", nameof(rating)); } - public int CompareTo(object? obj) - { - if (obj == null) - { - return 1; - } - - if (obj is RatingInformation other) - { - return CompareTo(other); - } - - throw new ArgumentException("A RatingInformation object is required for comparison.", "obj"); - } + Rating = v; + } - public int CompareTo(RatingInformation? other) + public int CompareTo(object? obj) + { + if (obj == null) { - if (other is null) - { - return 1; - } - - // Ratings compare opposite to normal string order, - // so reverse the value returned by String.CompareTo. - return -string.Compare(this.Rating, other.Rating, StringComparison.OrdinalIgnoreCase); + return 1; } - public static int Compare(RatingInformation left, RatingInformation right) + if (obj is RatingInformation other) { - if (object.ReferenceEquals(left, right)) - { - return 0; - } - if (left is null) - { - return -1; - } - return left.CompareTo(right); + return CompareTo(other); } - // Omitting Equals violates rule: OverrideMethodsOnComparableTypes. - public override bool Equals(object? obj) - { - if (obj is RatingInformation other) - { - return this.CompareTo(other) == 0; - } - - return false; - } + throw new ArgumentException("A RatingInformation object is required for comparison.", nameof(obj)); + } - // Omitting getHashCode violates rule: OverrideGetHashCodeOnOverridingEquals. - public override int GetHashCode() + public int CompareTo(RatingInformation? other) + { + if (other is null) { - char[] c = this.Rating.ToCharArray(); - return (int)c[0]; + return 1; } - // Omitting any of the following operator overloads - // violates rule: OverrideMethodsOnComparableTypes. - public static bool operator ==(RatingInformation left, RatingInformation right) + // Ratings compare opposite to normal string order, + // so reverse the value returned by String.CompareTo. + return -string.Compare(Rating, other.Rating, StringComparison.OrdinalIgnoreCase); + } + + public static int Compare(RatingInformation left, RatingInformation right) + { + if (object.ReferenceEquals(left, right)) { - if (left is null) - { - return right is null; - } - return left.Equals(right); + return 0; } - public static bool operator !=(RatingInformation left, RatingInformation right) + if (left is null) { - return !(left == right); + return -1; } - public static bool operator <(RatingInformation left, RatingInformation right) + return left.CompareTo(right); + } + + // Omitting Equals violates rule: OverrideMethodsOnComparableTypes. + public override bool Equals(object? obj) + { + if (obj is RatingInformation other) { - return (Compare(left, right) < 0); + return CompareTo(other) == 0; } - public static bool operator >(RatingInformation left, RatingInformation right) + + return false; + } + + // Omitting getHashCode violates rule: OverrideGetHashCodeOnOverridingEquals. + public override int GetHashCode() + { + char[] c = Rating.ToCharArray(); + return (int)c[0]; + } + + // Omitting any of the following operator overloads + // violates rule: OverrideMethodsOnComparableTypes. + public static bool operator ==(RatingInformation left, RatingInformation right) + { + if (left is null) { - return (Compare(left, right) > 0); + return right is null; } + return left.Equals(right); } - // + public static bool operator !=(RatingInformation left, RatingInformation right) + { + return !(left == right); + } + public static bool operator <(RatingInformation left, RatingInformation right) + { + return (Compare(left, right) < 0); + } + public static bool operator >(RatingInformation left, RatingInformation right) + { + return (Compare(left, right) > 0); + } +} +// - // - public class Test +// +public class TestCompare +{ + public static void Main1036(params string[] args) { - public static void Main1036(string[] args) + if (args.Length < 2) { - if (args.Length < 2) - { - Console.WriteLine("usage - TestRatings string 1 string2"); - return; - } - RatingInformation r1 = new RatingInformation(args[0]); - RatingInformation r2 = new RatingInformation(args[1]); - string answer; - - if (r1.CompareTo(r2) > 0) - answer = "greater than"; - else if (r1.CompareTo(r2) < 0) - answer = "less than"; - else - answer = "equal to"; - - Console.WriteLine("{0} is {1} {2}", r1.Rating, answer, r2.Rating); + return; } + RatingInformation r1 = new(args[0]); + RatingInformation r2 = new(args[1]); + string answer; + + if (r1.CompareTo(r2) > 0) + answer = "greater than"; + else if (r1.CompareTo(r2) < 0) + answer = "less than"; + else + answer = "equal to"; + + Console.WriteLine("{0} is {1} {2}", r1.Rating, answer, r2.Rating); } - // } +// diff --git a/docs/fundamentals/code-analysis/quality-rules/snippets/vb/all-rules/Program.vb b/docs/fundamentals/code-analysis/quality-rules/snippets/vb/all-rules/Program.vb new file mode 100644 index 0000000000000..ce1cd9c2960e5 --- /dev/null +++ b/docs/fundamentals/code-analysis/quality-rules/snippets/vb/all-rules/Program.vb @@ -0,0 +1,5 @@ +Public Class Program + Public Shared Sub Main() + TestCompare.Main1036(New String() {"C", "B"}) + End Sub +End Class diff --git a/docs/fundamentals/code-analysis/quality-rules/snippets/vb/all-rules/all-rules.vbproj b/docs/fundamentals/code-analysis/quality-rules/snippets/vb/all-rules/all-rules.vbproj index 0f5343a149b29..a108957937cbd 100644 --- a/docs/fundamentals/code-analysis/quality-rules/snippets/vb/all-rules/all-rules.vbproj +++ b/docs/fundamentals/code-analysis/quality-rules/snippets/vb/all-rules/all-rules.vbproj @@ -4,12 +4,9 @@ Exe all_rules net8.0 + $(NoWarn);SYSLIB0050 - - - - diff --git a/docs/fundamentals/code-analysis/quality-rules/snippets/vb/all-rules/ca1003-use-generic-event-handler-instances_1.vb b/docs/fundamentals/code-analysis/quality-rules/snippets/vb/all-rules/ca1003-use-generic-event-handler-instances_1.vb index 4394e9d21e541..ea5fd681e4b24 100644 --- a/docs/fundamentals/code-analysis/quality-rules/snippets/vb/all-rules/ca1003-use-generic-event-handler-instances_1.vb +++ b/docs/fundamentals/code-analysis/quality-rules/snippets/vb/all-rules/ca1003-use-generic-event-handler-instances_1.vb @@ -42,7 +42,7 @@ Namespace ca1003 Class Test - Shared Sub Main() + Shared Sub Main1003() Dim eventRaiser As New ClassThatRaisesEvent() Dim eventHandler As New ClassThatHandlesEvent(eventRaiser) diff --git a/docs/fundamentals/code-analysis/quality-rules/snippets/vb/all-rules/ca1036.vb b/docs/fundamentals/code-analysis/quality-rules/snippets/vb/all-rules/ca1036.vb new file mode 100644 index 0000000000000..553bdf81e5e8d --- /dev/null +++ b/docs/fundamentals/code-analysis/quality-rules/snippets/vb/all-rules/ca1036.vb @@ -0,0 +1,101 @@ + +' +Imports System.Globalization + +Public Class RatingInformation + Implements IComparable + Implements IComparable(Of RatingInformation) + + Public Sub New(rating As String) + ArgumentNullException.ThrowIfNull(rating) + + Dim v As String = rating.ToUpper(CultureInfo.InvariantCulture) + If (v.Length <> 1 Or + String.Compare(v, "C", StringComparison.Ordinal) > 0 Or + String.Compare(v, "A", StringComparison.Ordinal) < 0) Then + Throw New ArgumentException("Invalid rating value was specified.", NameOf(rating)) + End If + + Me.Rating = v + End Sub + + Public ReadOnly Property Rating As String + + Public Function CompareTo(obj As Object) As Integer Implements IComparable.CompareTo + If (obj Is Nothing) Then Return 1 + If (TypeOf obj IsNot RatingInformation) Then Return 0 + Dim other As RatingInformation = DirectCast(obj, RatingInformation) + Return CompareTo(other) + End Function + + Public Function CompareTo(other As RatingInformation) As Integer Implements IComparable(Of RatingInformation).CompareTo + If (other Is Nothing) Then Return 1 + ' Ratings compare opposite To normal String order, + ' so reverse the value returned by String.CompareTo. + Return -String.Compare(Rating, other.Rating, StringComparison.OrdinalIgnoreCase) + End Function + + Public Shared Operator =(one As RatingInformation, other As RatingInformation) As Boolean + If (one Is Nothing) Then Return (other Is Nothing) + If (other Is Nothing) Then Return False + Return (one.Rating = other.Rating) + End Operator + + Public Shared Operator <>(one As RatingInformation, other As RatingInformation) As Boolean + If (one Is Nothing) Then Return (other IsNot Nothing) + If (other Is Nothing) Then Return True + Return (one.Rating <> other.Rating) + End Operator + + Public Shared Operator <(one As RatingInformation, other As RatingInformation) As Boolean + If (one Is Nothing) Then Return (other IsNot Nothing) + If (other Is Nothing) Then Return False + Return (one.Rating < other.Rating) + End Operator + + Public Shared Operator >(one As RatingInformation, other As RatingInformation) As Boolean + If (one Is Nothing) Then Return False + If (other Is Nothing) Then Return True + Return (one.Rating > other.Rating) + End Operator + + Public Overrides Function Equals(obj As Object) As Boolean + If ReferenceEquals(Me, obj) Then + Return True + End If + + If obj Is Nothing Then + Return False + End If + + Throw New NotImplementedException() + End Function + + Public Overrides Function GetHashCode() As Integer + Throw New NotImplementedException() + End Function +End Class +' + +' +Public Class TestCompare + Public Shared Sub Main1036(ByVal args As String()) + If (args.Length < 2) Then + Return + End If + Dim r1 As New RatingInformation(args(0)) + Dim r2 As New RatingInformation(args(1)) + Dim answer As String + + If (r1.CompareTo(r2) > 0) Then + answer = "greater than" + ElseIf (r1.CompareTo(r2) < 0) Then + answer = "less than" + Else + answer = "equal to" + End If + + Console.WriteLine("{0} is {1} {2}", r1.Rating, answer, r2.Rating) + End Sub +End Class +' diff --git a/docs/fundamentals/code-analysis/quality-rules/snippets/vb/all-rules/ca2237-mark-iserializable-types-with-serializableattribute_1.vb b/docs/fundamentals/code-analysis/quality-rules/snippets/vb/all-rules/ca2237-mark-iserializable-types-with-serializableattribute_1.vb index f2b2bf5ba7f10..c07faa5d2aa3c 100644 --- a/docs/fundamentals/code-analysis/quality-rules/snippets/vb/all-rules/ca2237-mark-iserializable-types-with-serializableattribute_1.vb +++ b/docs/fundamentals/code-analysis/quality-rules/snippets/vb/all-rules/ca2237-mark-iserializable-types-with-serializableattribute_1.vb @@ -1,6 +1,4 @@ -Imports System -Imports System.Runtime.Serialization -Imports System.Security.Permissions +Imports System.Runtime.Serialization Namespace ca2237 @@ -22,13 +20,11 @@ Namespace ca2237 End Sub Overridable Sub GetObjectData( - info As SerializationInfo, context As StreamingContext) _ - Implements ISerializable.GetObjectData + info As SerializationInfo, context As StreamingContext) Implements ISerializable.GetObjectData info.AddValue("baseValue", baseValue) End Sub - End Class End Namespace