C#   Уроки программирования с нуля. Си-шарп для чайников   C#

Здравствуйте, гость!
Вход
Регистрация


Переопределение методов Equals и GetHashCode в Си-шарп. Разница между Equals и «==»
Как известно, в Си-шарп все классы являются наследниками базового класса object. В нем есть три виртуальных метода – ToString, Equals и GetHashCode. В этом уроке мы поговорим с вами о последних двух методах, а также об операторе «==».

Скажу сразу, что вопрос разницы между оператором равенства «==» и методом Equals является классическим вопросом на собеседовании на вакансию программиста Си-шарп.

Оператор равенства «==»

По умолчанию при работе с ссылочными типами данных (все классы кроме string, интерфейсы, делегаты) оператор «==» проверяет равенство ссылок. Он возвращает true, когда обе ссылки указывают на один объект, в противном случае – false. Приведу код, который демонстрирует работу данного оператора с ссылочными типами:

static void Main(string[] args)
{
   object o1 = new object();
   object o2 = new object();
   object o3 = o1;
   Console.WriteLine(o1 == o2); // false
   Console.WriteLine(o1 == o3); // true
}

Здесь создается два объекта, ссылки на которые записываются в переменные o1 и o2. Дальше ссылка o1 копируется в переменную o3 (o1 и o3 указывают на один объект). В итоге имеем false при сравнении ссылок o1 и o2, и true при o1 и o3.

Метод Equals

Метод Equals принимает один аргумент – объект, который будет сравниваться с текущим объектом, и определяет, равны ли между собой эти объекты. Здесь уже идет речь о равенстве полей объектов, а не ссылок. Этот метод виртуальный, и его базовая реализация это просто проверка равенства ссылок оператором «==». Но когда мы создаем некий класс, и нам необходимо реализовать возможность проверки идентичности объектов, следует переопределить именно данный метод, а не воспользоваться перегрузкой оператора «==», чтобы не спутывать базовые назначения этих инструментов сравнивания.

Перегрузка метода Equals

При переопределении метода Equals следует позаботиться о том, чтобы этот метод возвращал false в случаях, когда в метод передано значение NULL, когда переданный объект нельзя привести к типу текущего объекта, ну и когда поля объектов отличаются.

Возьмем уже знакомый нам класс Money с предыдущего урока, и переопределим в нем метод Equals:

public class Money
{
   public decimal Amount { get; set; }
   public string Unit { get; set; }

   public Money(decimal amount, string unit)
   {
     Amount = amount;
     Unit = unit;
   }

  public override bool Equals(object obj)
   {
     if (obj == null)
       return false;
     Money m = obj as Money; // возвращает null если объект нельзя привести к типу Money
     if (m as Money == null)
       return false;

     return m.Amount == this.Amount && m.Unit == this.Unit;
   }
}
class Program
{
   static void Main(string[] args)
   {
     Money m1 = new Money(100, "RUR");
     Money m2 = new Money(100, "RUR");
     Money m3 = new Money(100, "USD");
     Money m4 = m1;
     Console.WriteLine(m1.Equals(m2)); // true
     Console.WriteLine(m1.Equals(m3)); // false
     Console.WriteLine(m1 == m2); // false
     Console.WriteLine(m1 == m4); // true
     Console.ReadLine();
   }
}

Как видим, в коде выше метод Equals и оператор «==» работают соответственно своим базовым определениям.

Также для повышения производительности при переопределении метода Equals рекомендуется перегружать его реализацией с типом аргумента соответствующему классу, в котором он переопределяется:

public bool Equals(Money obj) // аргумент типа Money
{
   if (obj == null)
     return false;

   return obj.Amount == this.Amount && obj.Unit == this.Unit;
}


Метод GetHashCode

Данный метод, как следует из его названия, возвращает хеш-код. Хеш-код это число соответствующее значению объекта. Это число мы получаем в результате работы некоторого метода, который должен обладать следующими свойствами:

- он должен возвращать одинаковый хеш-код каждый раз при вызове для одного и того же объекта.
- если имеется два равных (эквивалентных) объекта, то хеш-код для них должен быть одинаковым. Только это не означает, что если объекты неравны, то их хеш-коды обязательно будут разными.

Метод GetHashCode используется в таких структурах, как хэш-таблицы (Hashtable). Это мы сейчас рассматривать не будем, но корректность их работы стоит обеспечивать. Методы Equals и GetHashCode тесно связанны между собой, при переопределении одного из них, следует переопределять и другой. Базовая реализация метода GetHashCode в классе object очень условная, и она не обеспечивает второе свойство, когда одинаковые объекты имеют одинаковые хеш-коды.

static void Main(string[] args)
{
   Money m1 = new Money(100, "RUR");
   Money m2 = new Money(100, "RUR");
   Console.WriteLine(m1.GetHashCode()); // 456...
   Console.WriteLine(m2.GetHashCode()); // 411...
   Console.ReadLine();
}

Чтобы это исправить, мы переопределяем метод GetHashCode, и возвращаем хеш-код каким-либо способом, зависящим от поля/полей объекта:

public class Money
{
   public decimal Amount { get; set; }
   public string Unit { get; set; }

   public Money(decimal amount, string unit)
   {
     Amount = amount;
     Unit = unit;
   }

   public override bool Equals(object obj)
   {
     if (obj == null)
       return false;
     Money m = obj as Money;
     if (m as Money == null)
       return false;
     return m.Amount == this.Amount && m.Unit == this.Unit;
   }
public bool Equals(Money obj) // аргумент типа Money
   {
     if (obj == null)
     return false;
     return obj.Amount == this.Amount && obj.Unit == this.Unit;
   }
public override int GetHashCode()
   {
     int unitCode;
     if (Unit == "RUR")
       unitCode = 1;
     else unitCode = 2;
     return (int) Amount + unitCode;
   }

}
class Program
{
   static void Main(string[] args)
   {
     Money m1 = new Money(100, "RUR");
     Money m2 = new Money(100, "RUR");
     Money m3 = new Money(100, "USD");
     Console.WriteLine(m1.GetHashCode()); // 101
     Console.WriteLine(m2.GetHashCode()); // 101
     Console.WriteLine(m3.GetHashCode()); // 102
     Console.ReadLine();

   }
}

Здесь в качестве хеш-кода возвращается количество денег (целая часть) плюс код валюты. В результате теперь второе условие выполняется.

Домашнее задание

Создайте класс окружность с полями координаты центра и радиус и переопределите в нем корректно методы Equals и GetHashCode. Окружности равны если у них одинаковые координаты центра и радиусы.
Понравилась статья? Подпишись на рассылку и узнавай первым о новых уроках по почте!


Поделиться с друзьями:
16 мар 2014 05:10
Stavr 23 ноя 2016 07:51
ИМХО лучшее реализация "GetHashCode" приридумал SDenV 25 фев 2015 13:05. Плюсовать к друг дружке переменные не очень хорошая идея. Если их местами поменять тот же код получится :-/

public override int GetHashCode()
{
string s =string.Format("{0}{1}{2}", radius, centreX, centreY);
return Convert.ToInt32(s);
}

ProfessorWho 10 сен 2016 09:22

class Circle
{
public double radious { get; set; }
public int[] crdn = new int[2];
public Circle(double Rad,int CoordinateX,int CoordinateY)
{
crdn[0] = CoordinateX;
crdn[1] = CoordinateY;
radious = Rad;
}
public bool Equals(Circle obj)
{
if (obj == null)
return false;
return obj.radious == this.radious && obj.crdn[0] == this.crdn[0] && obj.crdn[1] == this.crdn[1];
}
public override int GetHashCode()
{
return (int)((radious / crdn[0]) * crdn[1]);
}
}
class Program
{
static void Main(string[] args)
{
Circle krug1 = new Circle(30, 32, 31);
Circle krug2 = new Circle(30, 32, 31);
Circle krug3 = new Circle(56, 1, 9);
Console.WriteLine(krug1.GetHashCode());
Console.WriteLine(krug2.GetHashCode());
Console.WriteLine(krug1.Equals(krug2));
Console.WriteLine(krug1.Equals(krug3));
Console.WriteLine(krug3.GetHashCode());
Console.ReadKey();
}
}

bas-tion.ru 09 май 2016 12:57

class Program
{
// Создайте класс окружность с полями координаты центра и радиус
// и переопределите в нем корректно методы Equals и GetHashCode.
// Окружности равны если у них одинаковые координаты центра и радиусы.

class Circle
{
// Объявляем поля класса, целочисленные, доступ к полям только внутри класса
private int CenterX;
private int CenterY;
private int Radius;

// Создаём конструктор для присвоения значений полям при инициализации
public Circle(int aCenterX , int aCenterY, int aRadius)
{
CenterX = aCenterX;
CenterY = aCenterY;
Radius = aRadius;
}

// Создаём метод с именем Equals, в качестве аргумента (Circle anObj) - объект
// класса Circle. Метод будет сравнивать поля текущего объекта (this)
// и указанного в качестве аргумента (anObj) используя "==". Возвращается bool
public bool Equals(Circle anObj)
{
if (anObj == null)
return false;
return anObj.CenterX == this.CenterX &&
anObj.CenterY == this.CenterY &&
anObj.Radius == this.Radius;
}

// Перегружаем GetHashCode - наследуется от класса Object
// После перегрузки будет возвращать сумму всех полей.
public override int GetHashCode()
{
return (int)CenterX + CenterY + Radius;
}
}

static void Main(string[] args)
{
// Создаём две окружности
Circle myCricle1 = new Circle(10, 10, 4);
Circle myCricle2 = new Circle(10, 10, 4);

// Выводим Hash
Console.WriteLine(myCricle1.GetHashCode());
Console.WriteLine(myCricle2.GetHashCode());

// Проверяем, равны ли они и выводим в консоль
Console.WriteLine(myCricle1.Equals(myCricle2));

//
Console.ReadKey();
}
}

игорь 02 фев 2016 10:54

namespace ConsoleApplication70
{
class Circle
{
internal int centr_x;
internal int centr_y;
internal int Radius;

public Circle(int x, int y, int R)
{
centr_x = x;
centr_y = y;
Radius = R;
}

public override bool Equals(object obj)
{
if (obj == null)
return false;
Circle c = obj as Circle;
if (c == null)
return false;
return c.centr_x == this.centr_x && c.centr_y == this.centr_y && c.Radius == this.Radius;

}
public override int GetHashCode()
{

return centr_x + centr_y + Radius;

}

}
class Program
{
static void Main(string[] args)
{
Circle one = new Circle(10, 10, 10);
Circle two = new Circle(10, 10, 10);
Circle three = new Circle(11, 10, 10);
Console.WriteLine(one.Equals(two));
Console.WriteLine(one.Equals(three));
Console.WriteLine(one.GetHashCode());
Console.WriteLine(three.GetHashCode());
}
}
}

Nick 25 янв 2016 10:01
почему бы в проверке
Money m = obj as Money;
if (m as Money == null)
return false;
не писать сразу так:
Money m = obj as Money;
if (m == null)
return false;
?

Евгений 10 янв 2016 17:51

public static void Main(string[] args)
{
Circle pCirc1 = new Circle(10,10,5);
Circle pCirc2 = new Circle(10,5,10);
Circle pCirc3 = new Circle(10,1,5);
Circle pCirc4 = new Circle(10,10,5);
Console.WriteLine("Equals");
Console.WriteLine("pCirc1.Equals(pCirc2) : " + pCirc1.Equals(pCirc2));
Console.WriteLine("pCirc1.Equals(pCirc3) : " + pCirc1.Equals(pCirc3));
Console.WriteLine("pCirc1.Equals(pCirc4) : " + pCirc1.Equals(pCirc4));
Console.WriteLine("pCirc2.Equals(pCirc3) : " + pCirc2.Equals(pCirc3));
Console.WriteLine("pCirc2.Equals(pCirc4) : " + pCirc2.Equals(pCirc4));
Console.WriteLine("pCirc3.Equals(pCirc4) : " + pCirc3.Equals(pCirc4));
Console.WriteLine("\r\n\r\nHash");
Console.WriteLine("pCirc1.GetHashCode() : " + pCirc1.GetHashCode());
Console.WriteLine("pCirc2.GetHashCode() : " + pCirc2.GetHashCode());
Console.WriteLine("pCirc3.GetHashCode() : " + pCirc3.GetHashCode());
Console.WriteLine("pCirc4.GetHashCode() : " + pCirc4.GetHashCode());
Console.ReadKey();
}

public class Circle
{
public double nX{set;get;}
public double nY{set;get;}
public double nR{set;get;}

public Circle()
{

}
public Circle(int x, int y, int r)
{
this.nX = x;
this.nY = y;
this.nR = r;
}

public bool Equals(Circle pCirc)
{
if(this.nX == pCirc.nX && this.nY == pCirc.nY && this.nR == pCirc.nR)
{
return true;
}
return false;
}

public override int GetHashCode()
{
return (int)(this.nX*this.nY*this.nR);
}
}

Kolsky 03 янв 2016 15:30

/*
* Created by SharpDevelop.
* User: Kolsky
* Date: XX.XX.XXXX
* Time: XX:YY
*
* To change this template use Tools | Options | Coding | Edit Standard Headers.
*/
using System;

namespace a
{
class Circle
{
public Circle(){}
public Circle(int r, double x, double y)
{
this.Centre_X=x;
this.Centre_Y=y;
this.Radius=r;
}
public double Radius;
public double Centre_X;
public double Centre_Y;
public Boolean Equals(Circle a)
{
if(a==null) return false;
return a.Centre_X==this.Centre_X && a.Centre_Y == this.Centre_Y && a.Radius == this.Radius;
}
public override bool Equals(object obj)
{
if (obj==null) return false;
Circle a=obj as Circle;
return a.Centre_X==this.Centre_X && a.Centre_Y == this.Centre_Y && a.Radius == this.Radius;
}
public override int GetHashCode()
{
return Convert.ToInt32(Radius+Centre_X+Centre_Y);
}
}
class Program
{
public static void Main(string[] args)
{
Circle C1=new Circle(5,0,0);
Circle C2=new Circle(5,0,0);
Circle C3=new Circle();
Circle C4=new Circle(4,8,5);
Console.Write((C1.Equals(C2)?"1 ":"0 ")+(C1.Equals(C3)?"1\r\n":"0\r\n"));
Console.Write(C4.GetHashCode()+", "+C1.GetHashCode());
Console.ReadKey(true);
}
}
}

Kolsky 03 янв 2016 15:30

/*
* Created by SharpDevelop.
* User: Kolsky
* Date: XX.XX.XXXX
* Time: XX:YY
*
* To change this template use Tools | Options | Coding | Edit Standard Headers.
*/
using System;

namespace a
{
class Circle
{
public Circle(){}
public Circle(int r, double x, double y)
{
this.Centre_X=x;
this.Centre_Y=y;
this.Radius=r;
}
public double Radius;
public double Centre_X;
public double Centre_Y;
public Boolean Equals(Circle a)
{
if(a==null) return false;
return a.Centre_X==this.Centre_X && a.Centre_Y == this.Centre_Y && a.Radius == this.Radius;
}
public override bool Equals(object obj)
{
if (obj==null) return false;
Circle a=obj as Circle;
return a.Centre_X==this.Centre_X && a.Centre_Y == this.Centre_Y && a.Radius == this.Radius;
}
public override int GetHashCode()
{
return Convert.ToInt32(Radius+Centre_X+Centre_Y);
}
}
class Program
{
public static void Main(string[] args)
{
Circle C1=new Circle(5,0,0);
Circle C2=new Circle(5,0,0);
Circle C3=new Circle();
Circle C4=new Circle(4,8,5);
Console.Write((C1.Equals(C2)?"1 ":"0 ")+(C1.Equals(C3)?"1\r\n":"0\r\n"));
Console.Write(C4.GetHashCode()+", "+C1.GetHashCode());
Console.ReadKey(true);
}
}
}

ROOT 30 авг 2015 15:51
//Домашнее задание//

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
class Circle
{
public double Center_x { get; set; }
public double Center_y { get; set; }
public double Radius { get; set; }
public Circle(double x, double y, double rad)
{
Center_x = x;
Center_y = y;
Radius = rad;
}
public override bool Equals(object obj)
{
if (obj == null)
return false;
Circle c = obj as Circle;
if (c as Circle == null)
return false;
return c.Center_x == this.Center_x && c.Center_y == this.Center_y && c.Radius == this.Radius;
}
public bool Equals(Circle obj)
{
if (obj == null)
return false;
return obj.Center_x == this.Center_x && obj.Center_y == this.Center_y && obj.Radius == this.Radius;
}
public override int GetHashCode()
{
return (int)Center_x + (int)Center_y + (int)Radius;
}
}
class Program
{
static void Main(string[] args)
{
Circle cr1 = new Circle(12, 14, 20);
Circle cr2 = new Circle(21, 32, 56);
Circle cr3 = new Circle(12, 14, 20);
Circle cr4 = new Circle(48, 59, 70);
Console.WriteLine("Сравнение:1-ой и 2-ой окружности: " + cr1.Equals(cr2));
Console.WriteLine("Сравнение:2-ой и 3-ей окружности: " + cr2.Equals(cr3));
Console.WriteLine("Сравнение:1-ой и 3-ей окружности: " + cr1.Equals(cr3));
Console.WriteLine("Сравнение:2-ой и 4-ой окружности: " + cr2.Equals(cr4));
Console.WriteLine("\nХеш-код 1-ой окружности: " + cr1.GetHashCode());
Console.WriteLine("Хеш-код 2-ой окружности: " + cr2.GetHashCode());
Console.WriteLine("Хеш-код 3-ей окружности: " + cr3.GetHashCode());
Console.WriteLine("Хеш-код 4-ой окружности: " + cr4.GetHashCode());
Console.ReadKey();
}
}
}

Александр_Бугай 18 май 2015 19:57
class Circle
{
public double Center{get;set;}
public double Radius { get; set; }
public Circle(double center, double radius)
{
Center = center;
Radius = radius;
}
public override bool Equals(object obj)
{
if (obj == null)
return false;
Circle c = obj as Circle;
if (c as Circle == null)
return false;
return c.Center == this.Center && c.Radius == this.Radius;
}
public override int GetHashCode()
{
return (int)Radius + (int)Center;
}


}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Input center of the first circle");
double cir1 = Convert.ToDouble(Console.ReadLine());
Console.WriteLine("Input radius of the first circle");
double rad1 = Convert.ToDouble(Console.ReadLine());
Circle c1 = new Circle(cir1, rad1);
Console.WriteLine("Input center of the second circle");
double cir2 = Convert.ToDouble(Console.ReadLine());
Console.WriteLine("Input radius of the second circle");
double rad2 = Convert.ToDouble(Console.ReadLine());
Circle c2 = new Circle(cir2, rad2);
if (c1.Equals(c2) == true && c1.GetHashCode() == c2.GetHashCode())
{
Console.WriteLine(c1.GetHashCode());
Console.WriteLine("They are equality");
}
else
{
Console.WriteLine("They are different");
Console.WriteLine("Equals - " + c1.Equals(c2));
Console.WriteLine("Hash1 = " + c1.GetHashCode());
Console.WriteLine("Has2 = " + c1.GetHashCode());
}

Console.ReadLine();
}
}

Азиз 18 май 2015 19:27
Максим
---
Да, проглупил насчет условия :)
А насчет центра - я образно, принцип от этого не меняется

Максим 17 май 2015 18:37
Азиз
---
В методе GetHashCode не нужно никаких условий, здесь достаточно было бы вернуть сумму радиуса и центра (центр у вас непонятный, предпологалась точка x,y).

Азиз 17 май 2015 14:45
Вот, пожалуйста проверьте.

class Program
{
public static void Main(string[] args)
{
Circle c1 = new Circle(40,100);
Circle c2 = new Circle(50,100);
Circle c3 = new Circle(40,100);
Console.WriteLine(c1.Equals(c2)); // false
Console.WriteLine(c1.Equals(c3)); // true
Console.WriteLine(c1.GetHashCode()); //100
Console.ReadLine();
}
}
class Circle
{
public int Center;
public int Radius;

public Circle(int center, int radius)
{
this.Center = center;
this.Radius = radius;
}
public override bool Equals(object obj)
{
if (obj is Circle) {
return ((obj as Circle).Center == this.Center && (obj as Circle).Radius == this.Radius);
}
else
{
return false;
}

}
public override int GetHashCode()
{
if (this.Center == 40 && this.Radius == 100) {
return 100;
}
else{
return 0;
}
}

}

SDenV 25 фев 2015 13:05
Вроде бы, правильно сделал. Спасибо за уроки

class Program

{

static void Main(string[] args)

{

Circle c = new Circle(2, 5, 5);

Circle c1 = new Circle(5, 6, 6);

Circle c2 = new Circle(5, 6, 6);



Console.WriteLine((c1.Equals(c2)) ? c1.GetHashCode() : c.GetHashCode());

Console.WriteLine((c.Equals(c1)) ? c1.GetHashCode() : c.GetHashCode());

}

}

class Circle

{

int radius { get; set; }

int centreX { get; set; }

int centreY { get; set; }



public Circle(int radius, int centreX, int centreY)

{

this.radius = radius;

this.centreX = centreX;

this.centreY = centreY;

}



public override int GetHashCode()

{

string s =string.Format("{0}{1}{2}", radius, centreX, centreY);

return Convert.ToInt32(s);

}

public override bool Equals(object obj)

{

if (obj == null)

return false;

Circle c = obj as Circle;

if (c as Circle == null)

return false;

return c.centreX == this.centreX && c.centreY == this.centreY && c.radius == this.radius;

}

public bool Equals(Circle obj)

{

if (obj == null)

return false;

return obj.radius == this.radius && obj.centreX == this.centreX && obj.centreY == this.centreY;

}

}

AlexWolf 25 фев 2015 09:14

namespace ConsoleApplication1
{
class Okruzhnost
{
public int CentrcoordX { get; set; }
public int CentrcoordY { get; set; }
public int Diametr { get; set; }
public Okruzhnost(int centrcoordX, int centrcoordY, int diametr)
{
CentrcoordX = centrcoordX;
CentrcoordY = centrcoordY;
Diametr = diametr;
}
public override bool Equals(object obj)
{
if (obj == null) { return false; }
Okruzhnost a = obj as Okruzhnost;
if (a as Okruzhnost == null) { return false; }
return a.CentrcoordX == this.CentrcoordX && a.CentrcoordY == this.CentrcoordY && a.Diametr == this.Diametr;
}
public bool Equals(Okruzhnost obj)
{
if (obj == null) { return false; }
return obj.CentrcoordX == this.CentrcoordX && obj.CentrcoordY == this.CentrcoordY && obj.Diametr == this.Diametr;
}
public override int GetHashCode()
{
int code = 1;
if (Diametr == 65 && CentrcoordX == 150 && CentrcoordY == 150)
{ code = 1; }
else { code = (CentrcoordX+CentrcoordY)*1000+Diametr; }
return (int)code;
}
}
class Program
{
static void Main(string[] args)
{
Okruzhnost ring1 = new Okruzhnost(150, 150, 65);
Okruzhnost ring2 = new Okruzhnost(150, 100, 65);
Okruzhnost ring3 = new Okruzhnost(150, 150, 65);
Okruzhnost ring4 = ring1;
Okruzhnost ring5 = new Okruzhnost(110, 170, 85);
Console.WriteLine(ring1.GetHashCode());
Console.WriteLine(ring2.GetHashCode());
Console.WriteLine(ring3.GetHashCode());
Console.WriteLine(ring4.GetHashCode());
Console.WriteLine(ring5.GetHashCode());
Console.WriteLine("равны ли 1 и 2 круг? "+ring1.Equals(ring2));
Console.WriteLine("равны ли 1 и 3 круг? " + ring1.Equals(ring3));
Console.WriteLine("равны ли 1 и 4 круг? " + ring1.Equals(ring4));
Console.WriteLine("равны ли 1 и 5 круг? " + ring1.Equals(ring5));
Console.ReadKey();
}
}
}



Максим 21 фев 2015 14:46
Виталий
---
У вас получилась очень громоздкая перегрузка метода GetHashCode, можно ведь проще. Урок "Работа со строками" читали? Вот как я заменил в вашей программе этот метод:

public override int GetHashCode()
{
string[] koordinats = centrekoordinats.Split(':');
return radius + Convert.ToInt32(centrekoordinats[0]) + Convert.ToInt32(centrekoordinats[1]);
}

Виталий 21 фев 2015 12:54
Оперативно исправил:

class circle
{
public int radius;
public string centrekoordinats;
public override bool Equals(object obj)
{
if (obj == null)
return false;
circle m = obj as circle;
if (m as circle == null)
return false;
return m.radius == this.radius && m.centrekoordinats == this.centrekoordinats;
}
public bool Equals(circle obj)
{
if (obj == null)
return false;
return obj.radius == this.radius && obj.centrekoordinats == this.centrekoordinats;
}
public override int GetHashCode()
{
int unitCode;
int unitcode;
switch (radius)
{
case 10:
unitCode = 10;
break;
case 11:
unitCode = 11;
break;
case 12:
unitCode = 12;
break;
case 13:
unitCode = 13;
break;
case 14:
unitCode = 14;
break;
case 15:
unitCode = 15;
break;
case 16:
unitCode = 16;
break;
case 17:
unitCode = 17;
break;
case 18:
unitCode = 18;
break;
case 19:
unitCode = 19;
break;
case 20:
unitCode = 20;
break;
default:
unitCode = 212;
break;
}
switch (centrekoordinats)
{
case "10:10":
unitcode = 20;
break;
case "11:11":
unitcode = 22;
break;
case "12:12":
unitcode = 24;
break;
case "13:13":
unitcode = 26;
break;
case "14:14":
unitcode = 28;
break;
case "15:15":
unitcode = 30;
break;
case "16:16":
unitcode = 32;
break;
case "17:17":
unitcode = 34;
break;
case "18:18":
unitcode = 36;
break;
case "19:19":
unitcode = 38;
break;
case "20:20":
unitcode = 40;
break;
default:
unitcode = 212;
break;
}
return (int)unitcode + unitCode;
}

public circle(int radius, string centrekoordinats)
{
this.radius = radius;
this.centrekoordinats = centrekoordinats;
}

}
class Program
{
static void Main(string[] args)
{
circle circle1 = new circle(15, "10:10");
circle circle2 = new circle(15, "10:10");
circle circle3 = new circle(21, "21:21");
circle circle4 = new circle(18, "12:12");
Console.WriteLine(circle1.GetHashCode());
Console.WriteLine(circle2.GetHashCode());
Console.WriteLine(circle3.GetHashCode());
Console.WriteLine(circle4.GetHashCode());
Console.ReadKey();

}
}

Максим 20 фев 2015 20:53
Виталий
---
Конструктор пустой, поля не инициализирует:

public circle(int radius, string centrekoordinats)
{
this.radius = radius;
this.centrekoordinats = centrekoordinats;
}

Ну и не нужно создавать поле HashCode, это значение должен возвращать метод GetHashCode:

Console.WriteLine(circle1.GetHashCode());

Виталий 20 фев 2015 18:28
Подскажите пожалуйста, почему выдает 0? Пытался переписать return. Но все равно не работает.

class circle
{
public int radius;
public string centrekoordinats;
public override bool Equals(object obj)
{
if (obj == null)
return false;
circle m = obj as circle;
if (m as circle == null)
return false;
return m.radius == this.radius && m.centrekoordinats == this.centrekoordinats;
}
public bool Equals(circle obj)
{
if (obj == null)
return false;
return obj.radius == this.radius && obj.centrekoordinats == this.centrekoordinats;
}
public int HashCode;
public int unitcode;
public int unitCode;

public override int GetHashCode()
{
if (centrekoordinats == "1:1")
unitCode = 11;
if (centrekoordinats == "2:2")
unitCode = 22;
if (centrekoordinats == "3:3")
unitCode = 33;
if (centrekoordinats == "4:4")
unitCode = 44;
if (centrekoordinats == "5:5")
unitCode = 55;
if (centrekoordinats == "6:6")
unitCode = 66;
if (centrekoordinats == "7:7")
unitCode = 77;
if (centrekoordinats == "8:8")
unitCode = 88;
if (centrekoordinats == "9:9")
unitCode = 99;
else
unitCode = 212;

if (radius == 11)
unitcode = 11;
if (radius == 12)
unitcode = 12;
if (radius == 13)
unitcode = 13;
if (radius == 14)
unitcode = 14;
if (radius == 15)
unitcode = 15;
if (radius == 16)
unitcode = 16;
if (radius == 17)
unitcode = 17;
if (radius == 18)
unitcode = 18;
if (radius == 19)
unitcode = 19;
else
unitcode = 212;
return HashCode = unitCode + unitcode;
}

public circle(int radius, string centrekoordinats)
{
}

}
class Program
{
static void Main(string[] args)
{
circle circle1 = new circle(15, "9:9");
circle circle2 = new circle(15, "6:6");
circle circle3 = new circle(15, "9:9");
circle circle4 = new circle(21, "12:12");
Console.WriteLine(circle1.HashCode);
Console.WriteLine(circle2.HashCode);
Console.WriteLine(circle3.HashCode);
Console.WriteLine(circle4.HashCode);
Console.ReadKey();

}
}

Диманиак 02 дек 2014 11:40
namespace ConsoleApplicationTest
{
public class Circle
{
int CenterX;
int CenterY;
int Radius;
public Circle(int centerX, int centerY, int radius)
{
CenterX = centerX;
CenterY = centerY;
Radius = radius;
}
public override bool Equals(object obj)
{
if (obj == null)
return false;
Circle c = obj as Circle;
if (c as Circle == null)
return false;
return c.CenterX == CenterX && c.CenterY == CenterY && c.Radius == Radius;
}
public bool Equals(Circle obj)
{
if (obj == null)
return false;
return obj.CenterX == CenterX && obj.CenterY == CenterY && obj.Radius == Radius;
}
public override int GetHashCode()
{
string vector = "("+CenterX.ToString() + "," + CenterY.ToString() + "," + Radius.ToString()+")";
return vector.GetHashCode();
}
}
class Program
{
static void Main(string[] args)
{
List<Circle> circles = new List<Circle>();
Circle circle1 = new Circle(111, 1, 111);
circles.Add(circle1);
circles.Add(new Circle(11, 11, 111));
circles.Add(new Circle(1, 1111, 11));
circles.Add(new Circle(111, 1, 111));
Circle circle2 = circle1;
circles.Add(circle2);
for (int i = 0; i < circles.Count; i++)
for (int j = i+1; j < circles.Count; j++)
{
Console.WriteLine("Ref to Circle № " + (i + 1) + " " + (circles.ElementAt(i) == circles.ElementAt(j) ? "==" : "!=") + " Ref to Circle № " + (j + 1));
Console.WriteLine("Circle № " + (i + 1) + " " + (circles.ElementAt(i).Equals(circles.ElementAt(j)) ? "equals" : "not equals") + " Circle № " + (j + 1));
Console.WriteLine("HashCode of Circle № " + (i + 1) + " " + (circles.ElementAt(i).GetHashCode() == circles.ElementAt(j).GetHashCode() ? "==" : "!=") + " HashCode of Circle № " + (j + 1));
Console.WriteLine("");
Console.ReadLine();
}
}
}
}

Max 12 ноя 2014 10:28
Ясно, спасибо за ответ. То есть хеш там в принципе реализован, но майкрософт просто снимают с себя ответственность за его надежность и не указывают конкретный алгоритм.

Максим 11 ноя 2014 19:14
Max
---
Если не переопределять метод GetHashCode, он будет вычислять хеш алгоритмом по умолчанию, который не специфицирован (но не рандом). MSDN пишет:

"Реализация GetHashCode по умолчанию не гарантирует уникальные значения для различных объектов. Кроме того, .NET Framework не гарантирует, что реализация GetHashCode по умолчанию, в том числе значения, возвращаемые ей, не поменяются при смене версии фреймворка. Соответственно, значение функции GetHashCode по умолчанию не должно быть использована как уникальный идентификатор объекта с целью хеширования."

Когда же мы переопределяем этот метод, наш алгоритм хеширования может быть очень простым - одно поле объекта умноженное на другое и т. д.

Max 10 ноя 2014 20:14
Хотя реализация вычисления хеша в уроке говорит о том, что в данном случае под хеш-кодом подразумевается вовсе не тот хеш, который подразумевается всегда. Я подумал, что метод вычисляет хеш от входных данных по какому-то существующему алгоритму, но в данном случае это просто случайное число, так?

Max 10 ноя 2014 20:03
Поправьте статью:
"Только это не означает, что если объекты неравны, то их хеш-коды обязательно будут разными."
Хеши разных объектов (пусть даже отличных всего на 1 бит) ВСЕГДА будут отличаться очень сильно. Это главное требование к хешам с точки зрения криптографии. Исключения называются коллизиями, но их наличие считается несовершенством алгоритма хеширования (любого), а не нормой. И встречаются коллизии очень редко, для ориентира можно считать 1/(10^20), то есть сугубо теоретически.

why_not 08 ноя 2014 13:33
Оставил ошибку(когда centr = 1000*radius), т. к. не знаю, что такое хеш-таблицы и как они работают. В остальном, все сделал по примеру, но осознанно))


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;


namespace ConsoleApplication1
{
public class Circle
{
public int Centr { get; set; }
public int Radius { get; set; }
public Circle(int Centr, int Radius)
{
this.Centr = Centr;
this.Radius = Radius;
}
public override bool Equals(object obj)
{
if (obj == null)
return false;
Circle c = obj as Circle;
if (c as Circle == null)
return false;
return c.Centr == this.Centr && c.Radius == this.Radius;
}
public bool Equals(Circle obj)
{
if (obj == null)
return false;
return obj.Centr == this.Centr && obj.Radius == this.Radius;
}

public override int GetHashCode()
{
return (int) Centr * 1000 + Radius;
}

}
class Program
{
static void Main(string[] args)
{
Circle c1 = new Circle(50, 100);
Circle c2 = new Circle(50, 100);
Circle c3 = new Circle(60, 30);
Circle c4 = c1;
Console.WriteLine(c1.Equals(c2));
Console.WriteLine(c1.Equals(c3));
Console.WriteLine(c1 == c2);
Console.WriteLine(c1 == c4);
Console.WriteLine(c1.GetHashCode());
Console.WriteLine(c2.GetHashCode());
Console.WriteLine(c3.GetHashCode());
Console.ReadLine();

}
}
}

why_not 25 окт 2014 20:28
int unitCode;
if (Unit == "RUR")
unitCode = 1;
else unitCode = 2;
return (int) Amount + unitCode;

Возникает проблема, когда unitCode == Amount. (Например:Хешкод(2 RUR) ==хешкоду от (1 USD))

Максим 28 сен 2014 20:10
Firik
---
Для собственных классов да, сравнивают ссылки

Firik 27 сен 2014 09:17
То есть получается, что если не переопределять методы "==" и Equals, то они работают идентично?
using System;
class SampleClass
{
public static void Main()
{
Object obj1 = new Object();
Object obj2 = new Object();
Console.WriteLine(obj1.Equals(obj2));
obj1 = obj2;
Console.WriteLine(obj1.Equals(obj2));
}
}

beronny 09 сен 2014 19:05
class Okrujnost
{
public double X { get; set; }
public double Y { get; set; }
public double R { get; set; }

public Okrujnost(double x, double y, double r)
{
this.X = x;
this.Y = y;
this.R = r;
}

public override bool Equals(object obj)
{
if (obj == null)
return false;
Okrujnost o = obj as Okrujnost;
if (o == null)
return false;
return o.X == this.X && o.Y == this.Y && o.R == this.R;
}

public bool Equals(Okrujnost obj)
{
if (obj == null)
return false;
return obj.X == this.X && obj.Y == this.Y && obj.R == this.R;
}

public override int GetHashCode()
{
int unitCode;
unitCode = (int)X + (int)Y + (int)R;
return unitCode;
}


}
class Program
{
static void Main(string[] args)
{
Okrujnost okr1 = new Okrujnost(1.4, 2.1, 4);
Okrujnost okr2 = new Okrujnost(3.8, 2.2, 2.7);
Okrujnost okr3 = new Okrujnost(1.4, 2.1, 4);
Okrujnost okr4 = new Okrujnost(3, 44, 3);

Console.WriteLine("okr1 " + okr1.GetHashCode());
Console.WriteLine("okr2 " + okr2.GetHashCode());
Console.WriteLine("okr3 " + okr3.GetHashCode());
Console.WriteLine("okr4 " + okr4.GetHashCode());

Console.WriteLine(okr1.Equals(2));
Console.WriteLine(okr1.Equals(okr3));
Console.WriteLine(okr1.Equals(okr4));

Console.ReadKey();
}
}
}

Админ) так?

Максим 04 сен 2014 13:51
beronny
---
В уроке же об этом написано. "==" cравнивает ссылки для ссылочных типов, у каждого объекта она своя. Поэтому в первом случае false. Дальше m4 присвоили ссылку на m1, теперь они указывают на одну и ту же область памяти - одинаковые ссылки - true

beronny 04 сен 2014 12:24
Админ, помоги ещё! Почему здесь, когда мы сравниваем m1 и m2(m1 == m2), нам выдаёт False? они же одинаковые! ? c m1 и m4( m1 == m4 ) всё наоборот?


public class Money
{
public decimal Amount { get; set; }
public string Unit { get; set; }

public Money(decimal amount, string unit)
{
Amount = amount;
Unit = unit;
}

public override bool Equals(object obj)
{
if (obj == null)
return false;
Money m = obj as Money; // возвращает null если объект нельзя привести к типу Money
if (m as Money == null)
return false;

return m.Amount == this.Amount && m.Unit == this.Unit;
}
}
class Program
{
static void Main(string[] args)
{
Money m1 = new Money(100, "RUR");
Money m2 = new Money(100, "RUR");
Money m3 = new Money(100, "USD");
Money m4 = m1;
Console.WriteLine(m1.Equals(m2)); // true
Console.WriteLine(m1.Equals(m3)); // false
Console.WriteLine(m1 == m2); // false
Console.WriteLine(m1 == m4); // true
Console.ReadLine();
}
}


AlexSerikov 14 июл 2014 21:29
Учебником мне по голове за такой алгоритм с переопределением GetHashCode(), но я особо не думал, однако считаю идею с представлением координат центра с помощью 1-й переменной double очень интересной. Что думаете, уважаемый Admin ?

class Circle
{ // Координаты представлены с помощью переменной double
public double Center { get; set; } // Все, что до запятой - это координата по Х, а все, что после - координата по Y
public double Radius { get; set; }
public Circle(double Center, double Radius)
{
this.Center = Center;
this.Radius = Radius;
}
public override bool Equals(object obj)
{
if(obj==null)
return false;
Circle x = obj as Circle;
if(obj as Circle==null)
return false;
return x.Center == this.Center && x.Radius == this.Radius;
}
public bool Equals(Circle obj)
{
if (obj == null)
return false;
return obj.Center == this.Center && obj.Radius == this.Radius;
}
public override int GetHashCode()
{
double unitCode=Center+Radius;
return (int) unitCode;
}
}
class Program
{
static void Main()
{
Circle circle1 = new Circle(5.5, 3.0);
Circle circle2 = new Circle(5.5, 3.0);
Circle circle3 = new Circle(5.5, 1.0);
Circle circle4 = new Circle(4.4, 3.0);
Console.WriteLine("Сравниваем 1-й и 2-й круги:= "+circle1.Equals(circle2));
Console.WriteLine("Сравниваем 1-й и 3-й круги:= " + circle1.Equals(circle3));
Console.WriteLine("Сравниваем 1-й и 4-й круги:= " + circle1.Equals(circle4));
Console.WriteLine("----------------------------------");
Console.WriteLine("А теперь сверим HashCode объектов: ");
Console.WriteLine("circle 1 = " + circle1.GetHashCode());
Console.WriteLine("circle 2 = " + circle2.GetHashCode());
Console.WriteLine("circle 3 = " + circle3.GetHashCode());
Console.WriteLine("circle 4 = " + circle4.GetHashCode());
Console.ReadKey();
}
}

MrX 11 июн 2014 17:55
Проблема решена. Извините за беспокойство.

MrX 11 июн 2014 12:30
Объясните, пожалуйста, для чего в примере эта часть кода:
***
public bool Equals(Money obj) // аргумент типа Money
{
if (obj == null)
return false;
return obj.Amount == this.Amount && obj.Unit == this.Unit;
}
***
Ведь метод "Equals" нами уже переопределен перед этим.

Хотелось бы разобраться, потому что домашнее задание делал по данному примеру и оно не работает правильно: при вхождении в переопределенный метод "Equals" в строке: Money m = obj as Money;
объекту "m" не присваивается объект "obj" и Watch показывает, что после этой строки мой объект (образно говоря: "m") имеет значение "Null", соответственно дальше нужная часть кода не выполнятся.

Благодарен заранее за ответ.

Ромик 03 июн 2014 11:27
не хотелось бы захламлять, но мне тут намекнули, а я написал еще 1 интересный способ:
class First
{
public int number;
public short ordinal;
public string name;
public First(int number, short ordinal, string name)
{
this.number = number;
this.ordinal = ordinal;
this.name = name;
}
public override string ToString()
{
//string info;
//info = string.Format(this.number + "" + this.ordinal + this.name);
return this.number + "" + this.ordinal + this.name;//info;
}
public override bool Equals(object obj)
{
if (obj is First && obj != null)
{
if (this.ToString() == obj.ToString())
return true;
}
return false;
}
public override int GetHashCode()
{
return (this.ToString()).GetHashCode();
}
}

Максим 02 июн 2014 18:06
Ромик
---
Метод GetHashCode не принимает никаких аргументов:
public override int GetHashCode(object obj) // это попытка переопределить несуществующий метод

if (c1.Equals(c2) && c1.GetHashCode() == c2.GetHashCode()) // сравнивать хеш-коды не нужно, чтобы удостовериться в эквивалентности объектов достаточно c1.Equals(c2)

Ромик 02 июн 2014 11:01
Не понял, почему у меня была ошибка, но вот переделал, чтобы все заработало
class Circle
{
public double x;
public double y;
public double radius;
public Circle(double x, double y, double radius)
{
this.x = x;
this.y = y;
this.radius = radius;
}
public override bool Equals(object obj)
{
if (obj is Circle && obj != null)
{
if (this.x == (obj as Circle).x &&
this.y == (obj as Circle).y &&
this.radius == (obj as Circle).radius)
return true;
}
return false;
}
public override int GetHashCode()
{
int Code = 0;
Code = (int)x + (int)y + (int)radius;
return Code;
}
}
class Program
{
static void Main(string[] args)
{
Circle c1 = new Circle(2, 1.2, 5);
Circle c2 = new Circle(2, 1.2, 5);
if (c1.Equals(c2) && c1.GetHashCode() == c2.GetHashCode())
Console.WriteLine("Окружности равны");
else
Console.WriteLine("Окружности не равны");
Console.ReadKey();
}
}

Ромик 02 июн 2014 10:34
//2 ошибки
//1.Вы переопределили метод equals , но не переопределили метод GetHeshCode(в смысле это предупреждение)
//2. Project.Circle.GetHeshCode(object): не найден метод, пригодный для переопределения (это ошибка)
class Circle
{
public double x;
public double y;
public double radius;
public Circle(double x, double y, double radius)
{
this.x = x;
this.y = y;
this.radius = radius;
}
public override bool Equals(object obj)
{
if (obj is Circle && obj != null)
{
if (this.x == (obj as Circle).x &&
this.y == (obj as Circle).y &&
this.radius == (obj as Circle).radius)
return true;
}
return false;
}
public override int GetHashCode(object obj)
{
int Code = 0;
if (obj is Circle && obj != null)
{
Code = (int)(obj as Circle).x + (int)(obj as Circle).y + (int)(obj as Circle).radius;
}
return Code;
}
}
class Program
{
static void Main(string[] args)
{
Circle c1 = new Circle(2, 1.2, 5);
Circle c2 = new Circle(2, 1.2, 5);
Console.WriteLine(c1.GetHashCode());
Console.WriteLine(c2.GetHashCode());
if (c1.Equals(c2) && c1.GetHashCode(c1) == c2.GetHashCode(c2))
Console.WriteLine("Окружности равны");
Console.WriteLine("Окружности не равны");
Console.ReadKey();
}
}

Максим 26 мар 2014 00:04
Nadil
---
Вы говорите о перегрузке оператора "<<"? Такого в C# нет, можно лишь переопределять метод ToString но этого немного другое

Nadil 25 мар 2014 21:39
Круто) Все прочитал, почти как C++. Еще бы добавили перегрузку операторов вывода в консоль, допустим!


Добавить комментарий:

Имя (обязат.)
E-mail (обязат., не публикуется)


Для вставки ваших программ пользуйтесь кнопкой "исходный код"
Вёрстка сайта с нуля

Уникальный Видеокурс!

"Научись верстать сайты и заработай на этом!"

Получить видеокурс

Подпишись на курс по программированию, и узнавай первым о новых уроках!

RSS подписка Страничка Вконтакте Мы в Twitter
Бесплатный курс по основам PHP
Ошибка в тексте? Выделите ее мышкой и нажмите Ctrl+Enter
Поблагодарить автора: Номер карты (ПриватБанк)
5168 7572 4170 8660
WebMoney
R372544961915 U685637142028 Z999792764387
Наверх
Система Orphus