Last active
June 10, 2020 10:52
-
-
Save msedi/04c1e26366e58ac7ceb9e01b18f70dde to your computer and use it in GitHub Desktop.
Equals vs. == in struct comparison
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Diagnostics.CodeAnalysis; | |
using System.Globalization; | |
using System.Linq; | |
namespace ConsoleApp21 | |
{ | |
class Program | |
{ | |
static void Main(string[] args) | |
{ | |
RangeDescriptorGood good = new RangeDescriptorGood(); | |
Console.WriteLine("Comparison with =="); | |
Console.WriteLine($"Good == default: {good == default}"); | |
Console.WriteLine($"Good == null: {good == null}"); | |
Console.WriteLine(); | |
Console.WriteLine("Comparison with Equals"); | |
Console.WriteLine($"Good.Equals(default): {good.Equals(default)}"); | |
Console.WriteLine($"Good.Equals(null): {good.Equals(null)}"); | |
} | |
/// <summary> | |
/// Class that is able to resolve a range expression into an array of indices. | |
/// </summary> | |
public readonly struct RangeDescriptorGood : IEquatable<RangeDescriptorGood> | |
{ | |
private readonly bool IsInstance; | |
/// <summary> | |
/// List of Indices. | |
/// </summary> | |
public readonly string RangeString; | |
/// <summary> | |
/// ctor. | |
/// </summary> | |
/// <param name="indices"></param> | |
private RangeDescriptorGood(string rangeString) | |
{ | |
IsInstance = true; | |
RangeString = rangeString; | |
} | |
/// <summary> | |
/// | |
/// </summary> | |
/// <param name="v1"></param> | |
/// <param name="v2"></param> | |
public RangeDescriptorGood(int v1, int v2) | |
{ | |
IsInstance = true; | |
RangeString = $"{v1}-{v2}"; | |
} | |
/// <summary> | |
/// Parses a range expression, given in a-b, a-, -b, or in a comma separated list or both. | |
/// </summary> | |
/// <param name="rangeString_in"></param> | |
/// <param name="minVal"></param> | |
/// <param name="maxVal"></param> | |
/// <returns></returns> | |
public static RangeDescriptorGood Parse(string rangeString_in) | |
{ | |
if (string.IsNullOrEmpty(rangeString_in)) throw new ArgumentNullException(nameof(rangeString_in)); | |
return new RangeDescriptorGood(rangeString_in); | |
} | |
public int[] GetIndices(int minVal, int maxVal) | |
{ | |
string[] items = RangeString.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); | |
List<int> Indices = new List<int>(Math.Max(maxVal - minVal, 1)); | |
foreach (string item in items) | |
{ | |
if (!string.IsNullOrEmpty(item)) | |
{ | |
if (item.Contains('-')) | |
{ | |
string[] it = item.Split('-'); | |
string v1 = it[0].Trim(); | |
string v2 = it[1].Trim(); | |
int i1 = string.IsNullOrEmpty(v1) ? minVal : int.Parse(v1, NumberStyles.Integer, NumberFormatInfo.InvariantInfo); | |
int i2 = string.IsNullOrEmpty(v2) ? minVal : int.Parse(v2, NumberStyles.Integer, NumberFormatInfo.InvariantInfo); | |
// Swap if necessary. | |
if (i1 > i2) | |
{ | |
int tmp = i1; | |
i1 = i2; | |
i2 = tmp; | |
} | |
for (int idx = i1; idx <= i2; idx++) | |
{ | |
Indices.Add(idx); | |
} | |
} | |
else | |
{ | |
int idx = int.Parse(item, NumberStyles.Integer, NumberFormatInfo.InvariantInfo); | |
Indices.Add(idx); | |
} | |
} | |
} | |
// Sort the list, remove same values, shrink to valid range | |
#warning This has to be evaluated since it was meant that the range goes from min to max (including both) not excluding the end | |
return (from x in Indices orderby x ascending where (x >= minVal) && (x < maxVal) select x).Distinct().ToArray(); | |
} | |
/// <summary> | |
/// Evaluates the range and returns the indices that shall be evaluated. | |
/// </summary> | |
/// <param name="maxRangeItemsCount_in"></param> | |
/// <param name="range_in"></param> | |
/// <returns></returns> | |
public static IReadOnlyList<int> GetRangeIndex(int maxRangeItemsCount_in, RangeDescriptorGood range_in = default) | |
{ | |
List<int> aIndexes = new List<int>(); | |
// Get the necessary range | |
// If no range is given, we take the full range. | |
if (range_in == default) | |
{ | |
aIndexes.AddRange(Enumerable.Range(0, maxRangeItemsCount_in)); | |
} | |
// If a range is given, we need to interpret the values. | |
else | |
{ | |
aIndexes.AddRange(range_in.GetIndices(0, maxRangeItemsCount_in)); | |
} | |
return aIndexes; | |
} | |
/// <summary> | |
/// Maps the given range to a new range starting with a 0 target index. | |
/// </summary> | |
/// <param name="maxRangeItemsCount"></param> | |
/// <param name="range_in"></param> | |
/// <returns></returns> | |
public static IReadOnlyList<RangeItem> MapRange(int maxRangeItemsCount, RangeDescriptorGood range_in = default) | |
{ | |
List<RangeItem> aSourceToTargetIndices = new List<RangeItem>(); | |
var aIndexes = GetRangeIndex(maxRangeItemsCount, range_in); | |
for (int aTargetIndex = 0; aTargetIndex < aIndexes.Count; aTargetIndex++) | |
{ | |
aSourceToTargetIndices.Add(new RangeItem(aIndexes[aTargetIndex], aTargetIndex)); | |
} | |
return aSourceToTargetIndices; | |
} | |
/// <summary> | |
/// Checks for equality. | |
/// </summary> | |
/// <param name="obj"></param> | |
/// <returns></returns> | |
public override bool Equals(object obj) | |
{ | |
// If null is handed over, we assume that default was meant. | |
obj ??= default(RangeDescriptorGood); | |
if (!(obj is RangeDescriptorGood value)) | |
return false; | |
return Equals(value); | |
} | |
/// <summary> | |
/// Checks for equality. | |
/// </summary> | |
/// <param name="other"></param> | |
/// <returns></returns> | |
public bool Equals([AllowNull] RangeDescriptorGood other) | |
{ | |
if (!IsInstance && !other.IsInstance) | |
return true; | |
return string.Equals(RangeString, other.RangeString); | |
} | |
public override int GetHashCode() => RangeString.GetHashCode(); | |
public static bool operator ==(RangeDescriptorGood left, RangeDescriptorGood right) => Equals(left, right); | |
public static bool operator !=(RangeDescriptorGood left, RangeDescriptorGood right) => !Equals(left, right); | |
} | |
public readonly struct RangeItem | |
{ | |
public readonly int TargetIndex; | |
public readonly int SourceIndex; | |
public RangeItem(int sourceIndex_in, int targetIndex_in) | |
{ | |
TargetIndex = targetIndex_in; | |
SourceIndex = sourceIndex_in; | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment