0

Having some issues comparing 2 integer values.

public interface IData
{
  bool EqualsTo(IData otherData);
}

public class IntegerData : IData
{
  int _data;

  public IntegerData(int data)
  {
    _data = data;
  }

  public bool EqualsTo(IData otherData)
  {
    if(_data.CompareTo(otherData) == 0)
        return true;

    return false;
  }
}

I'm getting an error in the line:

if(_data.CompareTo(otherData) == 0)

Saying:

Object must of type int32

But in my watch window I can see both values are 10, and of Type int.

What's wrong?

My test:

IData FirstData = new IntegerData(5);
 IData FirstData = new SecondData(5);

 bool result = FirstData.Value.EqualsTo(SecondData.Value);
codecompleting
  • 9,251
  • 13
  • 61
  • 102

3 Answers3

3

I'll try to be as simple as possible:

This is what you are doing:

if ( <intValue>.CompareTo(<IData object>) == 0 )
{ (...) }

This is what you need:

if ( <intValue>.CompareTo(<int value>) == 0 )
{ (...) }

Now, here is how you can do it (very simplistic way):

public bool EqualsTo(IData otherData)
{
   if(_data.CompareTo(otherData._data) == 0)
      return true;
   return false;
}

This is another way to achieve the same (which I'd use for your scenario):

public interface IData : IEquatable<IData> { }

public class IntegerData : IData
{
   // The value will be private for this example
   // Could be public int Value { get; private set; }
   private int Value { get; set; }

   // Constructor
   public IntegerData(int value) { Value = value; }

   // Implements Equals (from IEquatable - IData)
   public bool Equals(IData other) 
   { return Value.Equals(other.Value); }
}

And this is another solution for the same task:
- Remember that this is a bigger solution for a somewhat small problem. This could lead to bigger classes and bigger problems so use it only if you need it. Be simple. Keep simple. Don't get into something too complex because you'll have to maintain that code over time...
- Also keep in mind that I've used the default "GetHashCode" method. Sometimes that's enough but keep in mind that you might need to create/use a custom hash algorithm depending on your need.
- Finally consider that this is just an example. I've created the interfaced based on Gabe's answer but added a method just for the hash itself. You might want to remove or improve. Consider your needs.

// An interface that is based on IEquatable for better compatibility but also
// enables you to create a diferent EqualsTo method...
public interface IData<T> : IEquatable<T>
{
   T GetData();
   int GetDataHash();
   bool EqualsTo(IData<T> other);
}

// One class (string)
public class StringData : IData<string>
{
   private string Value { get; set; }

   public StringData(string value) { Value = value; }

   public string GetData() { return Value; }
   public int GetDataHash() { return GetData().GetHashCode(); }

   // From IEquatable
   public bool Equals(string other)
   { return Value.Equals(other); }

   // From IData (customized to compare the hash from raw value)
   public bool EqualsTo(IData<string> other)
   { return GetDataHash() == other.GetDataHash(); }
}

// Another class (int)
public class IntData : IData<int>
{
   private int Value { get; set; }

   public IntData(int value) { Value = value; }

   public int GetData() { return Value; }
   public int GetDataHash() { return GetData().GetHashCode(); }

   // Again from IEquatable
   public bool Equals(int other)
   { return Value == other; }

   // Again from IData (customized to compare just the hash code)
   public bool EqualsTo(IData<int> other)
   { return GetDataHash() == other.GetDataHash(); }
}
Anderson Matos
  • 3,132
  • 1
  • 23
  • 33
1

You are comparing an integer to an IData object in the line that is throwing the exception. You need to cast the IData object to an IntegerData object and then compare it's _data property with the local _data property.

if(_data.CompareTo(((IntegerData)otherData)._data) == 0) 

A more elegant approach is to use generics to handle your varying type cases:

    public interface IData<T>
    {
        bool EqualsTo(IData<T> otherData);
    }

    public class MyData<T> : IData<T>
    {
        private T _data;

        public MyData(T data)
        {
            _data = data;
        }

        public bool EqualsTo(IData<T> otherData)
        {
            if (_data is IComparable 
                && otherData is MyData<T> 
                && ((IComparable)_data).CompareTo(((MyData<T>)otherData)._data) == 0)
            {  
                return true;
            }
            return false;
        }
    }

    static void Main(string[] args)
    {

        MyData<int> myInts1 = new MyData<int>(5);
        MyData<int> myInts2 = new MyData<int>(5);
        MyData<int> myInts3 = new MyData<int>(10);
        MyData<string> myString1 = new MyData<string>("Hello");
        MyData<string> myString2 = new MyData<string>("Hello");
        MyData<string> myString3 = new MyData<string>("World");
        if (myInts1.EqualsTo(myInts2)) Console.WriteLine("Yay");
        if (!myInts1.EqualsTo(myInts3)) Console.WriteLine("Nay");
        if (myString1.EqualsTo(myString2)) Console.WriteLine("Yay");
        if (!myString1.EqualsTo(myString3)) Console.WriteLine("Nay");
    }
Andy Rose
  • 16,770
  • 7
  • 43
  • 49
  • Good job echoing my interface example. – Gabe Oct 31 '11 at 17:18
  • -1 for "you are going to have to change it's protection level to do this or create a public property accessor". You don't. You never had to. Read about this here: http://stackoverflow.com/questions/614818/what-is-the-difference-between-public-private-protected-and-nothing – Anderson Matos Oct 31 '11 at 17:25
  • @LordALMMa - I took the approach of adding data to the interface so it would have to be public by default. If the data needs to remain private it can be done by casting the otherData object of the EqualTo method to the class expected and then access it privately that way. – Andy Rose Nov 01 '11 at 08:48
  • @AndyRose "_data must be public or interan for this to work" is mistaken too. However this approach now comes to a good solution. However I'd change the "private T _data;" to "private T _data { get; set; }" but there's up to you (it's private anyway but using get/set I can use aspects and dispatch events automaticaly). – Anderson Matos Nov 01 '11 at 11:46
0

otherData is of type IData

You would have to add a getter to get your int property so for the interface I add a GetData() method then implemented it in IntegerData

Something like this:

public interface IData<T>
{
  bool EqualsTo(IData otherData);
  T GetData();
}

public class IntegerData : IData<int>
{
  int _data;

  public int GetData(){
      return _data;
  }

  public IntegerData(int data)
  {
    _data = data;
  }

  public bool EqualsTo(IData otherData)
  {
    if(_data.CompareTo(otherData.GetData()) == 0)
        return true;

    return false;
  }
}
Gabe
  • 49,577
  • 28
  • 142
  • 181