2
using System;
using System.Collections.Generic;

//This is my class for obtaining certain values, putting them in a List<T>
//and then use the List to do certain operations 
public class SRvaluesChecker
{   
    double currentPriceValue;
    int totalVal, bullVal , bearVal , lineVal;

    //The List is of a custom object type
    List<MyValues> SRvalues = new List<MyValues>();

    for(int a = 0; a <= 1000; a++)
    {
        //Values are assigned to currentValue, totalVal, 
        //bullVal , bearVal and lineVal

    }

    //Check if the List has a particular value
    if(SRvalues.Exists(x => x.SRprice == currentPriceValue) == false)
    {
        //Do something
    }
}

//Here is the object I created so that I can store information of different
//data types in the list
public class MyValues : IEquatable<MyValues>
{   
    public override string ToString()
    {
        return "SRprice: " + SRprice + "   total count: " + totalCount + 
        "   bullish count: " + bullishCount + "   bearish count: " + bearishCount + 
        "   line type: " + lineType;
    }

    public MyValues(double SRprice, int totalCount, int bullishCount , int bearishCount, int lineType)
    {
        this.SRprice = SRprice;
        this.totalCount = totalCount;
        this.bullishCount = bullishCount;
        this.bearishCount = bearishCount;
        this.lineType = lineType;
    }

    public double SRprice { get; set; }
    public int totalCount { get; set; }
    public int bullishCount { get; set; }
    public int bearishCount { get; set; }
    public int lineType { get; set; } 

    public override bool Equals(object obj)
    {
        if (obj == null) return false;
        MyValues objAsPart = obj as MyValues;
        if (objAsPart == null) return false;
        else return Equals(objAsPart);
    }       

    //This currently only checks for one parameter (SRprice) but
    //I want to code for the others as well
    public bool Equals(MyValues other)
    {
        if (other == null) return false;
        return (this.SRprice.Equals(other.SRprice));
    }

    //Will override GetHashCode() and == and != operators later.        
}

As you can see from the code above, I have a custom object with 5 parameters and I want to be able to check for any one of them in the main class i.e.

if(SRvalues.Exists(x => x.SRprice == currentPriceValue))...
if(SRvalues.Exists(x => x.totalCount == totalVal))...
if(SRvalues.Exists(x => x.bullishCount == bullVal))...
if(SRvalues.Exists(x => x.bearishCount == bearVal))...
if(SRvalues.Exists(x => x.lineType == lineVal))...

but I am not sure how to go about coding for the Equals method so as to distinguish what parameter it is that I am checking for. Any help would be highly appreciated.

ivpavici
  • 1,117
  • 2
  • 19
  • 30

1 Answers1

0

You should not implement IEquatable.

Instead create a new class that implements IEqualityComparer<MyValues> and use this.

So let's start with a simple example:

public class MyClass
{
    public int First { get; set; }
    public string Second { get; set; }
    public decimal Third { get; set; }
}

Due to the fact, that we'd like to make our comparer configurable about which fields should be taken into account, we'll create an enum with bitfields for every available property:

[Flags]
public enum MyClassComparisonFields
{
    None = 0,
    First = 1,
    Second = 2,
    Third = 4,
    All = 7,
}

Now comes the important code, the equality comparer itself:

public class MyClassEqualityComparer : IEqualityComparer<MyClass>
{
    private MyClassComparisonFields _Comparisons;

    public MyClassComparer(MyClassComparisonFields comparisons)
    {
        _Comparisons = comparisons;
    }

    public bool Equals(MyClass x, MyClass y)
    {
        if(ReferenceEquals(x, y))
            return true;

        if(ReferenceEquals(x, null))
            return false;

        if(ReferenceEquals(y, null))
            return false;

        if(_Comparisons.HasFlag(MyClassComparisonFields.First))
        {
            if(!EqualityComparer<int>.Default.Equals(x.First, y.First))
                return false;
        }

        if(_Comparisons.HasFlag(MyClassComparisonFields.Second))
        {
            if(!EqualityComparer<string>.Default.Equals(x.Second, y.Second))
                return false;
        }

        if(_Comparisons.HasFlag(MyClassComparisonFields.Third))
        {
            if(!EqualityComparer<decimal>.Default.Equals(x.Third, y.Third))
                return false;
        }

        return true;
    }

    public int GetHashCode(MyClass x)
    {
        if(ReferenceEquals(x, null))
            return 0;

        int hash = 97463;

        if(_Comparisons.HasFlag(MyClassComparisonFields.First))
        {
            hash = hash * 99713 + x.First.GetHashCode();
        }

        if(_Comparisons.HasFlag(MyClassComparisonFields.Second)
           && x.Second != null)
        {
            hash = hash * 99713 + x.Second.GetHashCode();
        }

        if(_Comparisons.HasFlag(MyClassComparisonFields.Third))
        {
            hash = hash * 99713 + x.Third.GetHashCode();
        }

        return hash;
    }
}

You can instantiate an comparer and give it the desired fields you like (e.g. new MyClassEqualityComparer(MyClassComparisonFields.First | MyClassComparisonFields.Second)). This class can then be used in various places which takes an comparer as argument (like Dictionary<,>, HashSet<> or various LINQ extension methods) or call the method Equals() method on yourself for any objects you like to compare.

Be aware that a comparer must never throw an exception and must handle null values (as input parameter and child values of input parameter).

In your code you code take an instance which has the desired value(s) within the desired property(ies) and compare it with the desired comparer against your list:

var desiredMatch = GetDesiredSampleObject();
var comparer = new MyClassEqualityComparer(MyClassComparisonFields.First | MyClassComparisonFields.Third);
var listOfCandidates = GetAvailableCandidates();
var matches = listOfCandidates.Where(candidate => comparer.Equals(desiredMatch, candidate));

foreach(var match in matches)
{
    Console.WriteLine(match);
}
Oliver
  • 43,366
  • 8
  • 94
  • 151