class Super : IBase
{
public void Everything() { }
publicoverridebool Equals(Super other) { return true; }
}
ТС ещё кое-что забыл:
+ IEquatable<IBase>
+ GetHashCode()
+ операторы
+ sealed Super или аккуратная реализация операторов + override Equals и GetHashCode во всех наследниках.
Для простых случаев проще использовать свой IEqualityComparer<IBase>.
Re[8]: Вызов "неизвестного" метода Equals из шаблона
Здравствуйте, KA, Вы писали:
KA>Оказывается, метод попроще всё-таки есть. KA>он реализуется через интерфейс IEquatable<T>. KA>Ранее приведенный кусок кода надо дополнить всего парой строк (выделены жирным шрифтом), а именно: KA>
KA> class Super : IBase, System.IEquatable<Super>
KA> {
KA> public void Everything() { }
KA> public bool Equals(Super other) { return true; }
KA> }
KA>}
До конца не дочитали?
Примечания для разработчиков
Если реализуется интерфейс IEquatable<T>, следует также переопределить реализацию базового класса для методов Object.Equals(Object) и GetHashCode, чтобы их поведение соответствовало поведению метода IEquatable<T>.Equals.
Здравствуйте, KA, Вы писали:
KA>Всем привет, KA>Что надо скормить компилятору, чтобы подобные конструкции заработали? KA>Не хотелось бы вводить для этого интерфейс.
В constraint прописать базовый класс для итемов? Хотя, от введения интерефейса и его прописывания в constraint не сильно отличается.
class Container<T> : List<T> where T: Super
{
public void DoEverything()
{
foreach (T item in this)
item.Everything();
}
}
Или заюзать dynamic (в C# 4)
class Container<T> : List<T> where T : class
{
public void DoEverything()
{
foreach (dynamic item in this)
{
item.Everything();
}
}
}
Здравствуйте, KA, Вы писали:
KA>Что надо скормить компилятору, чтобы подобные конструкции заработали? KA>Не хотелось бы вводить для этого интерфейс.
конечно, вопрос из области теории но зачем так делать?
в одном месте:
foreach (T item in this)
item.Everything();
вы подразумеваете что элементы контейнера должны соответствовать (имеют метод everything) определенному контракту, но явно указывать это
(вводя интерфейс и указывать, в виде generic constraint, например) это не хотите. при том про динамическую типизацию и duck typing не пишите. что-то не так наверное.
KA>Я предполагаю, что в момент компиляции шаблона тип элементов действительно может быть не известен, но в точке инстанцирования уже все нужные классы видны полностью (их может быть несколько разных), так что компилятор должен догадаться, что нужный метод у класса элемента есть...
generics реализованы не как templates в C++. грубо говоря никакой текстовой подстановки и инстанцирования нет.
Здравствуйте, KA, Вы писали:
KA>Этот чудо-код компилируется, но всегда выдаёт False, поскольку всегда вызывается метод System.Object.Equals, который сравнивает значения ссылок.
class Super : IBase
{
public void Everything() { }
publicoverridebool Equals(Super other) { return true; }
}
using System.Collections.Generic;
namespace EqualsTest
{
class Super
{
public void Everything() { }
}
class Container<T> : List<T> where T: class
{
public void DoEverything()
{
foreach (T item in this)
item.Everything();
}
}
class Program
{
static void Main(string[] args)
{
Container<Super> con1 = new Container<Super>();
con1.Add(new Super());
con1.DoEverything();
}
}
}
который не компилируется из-за строки item.Everything() с ошибкой
UnknownTest.cs(14,14): error CS1061: 'T' does not contain a definition for 'Everything' and no extension method 'Everything' accepting a first argument of type 'T' could be found (are you missing a using directive or an assembly reference?)
Что надо скормить компилятору, чтобы подобные конструкции заработали?
Не хотелось бы вводить для этого интерфейс.
Я предполагаю, что в момент компиляции шаблона тип элементов действительно может быть не известен, но в точке инстанцирования уже все нужные классы видны полностью (их может быть несколько разных), так что компилятор должен догадаться, что нужный метод у класса элемента есть...
Заранее благодарю за ц.у. )
// #import <windows.bas> class IWindows9x:protected DOS { private: virtual HANDLE EnumClouds()=0; };
Здравствуйте, rasp_file, Вы писали:
KA>>Что надо скормить компилятору, чтобы подобные конструкции заработали? KA>>Не хотелось бы вводить для этого интерфейс.
_>Или заюзать dynamic (в C# 4) _>
_>class Container<T> : List<T> where T : class
_>{
_> public void DoEverything()
_> {
_> foreach (dynamic item in this)
_> {
_> item.Everything();
_> }
_> }
_>}
_>
Аха, интересный вариант, но учитывая, что dynamic "отключает" проверку типов во время компиляции, мне он не очень нравится — во время компиляции в моём случае уже всё известно...
// #import <windows.bas> class IWindows9x:protected DOS { private: virtual HANDLE EnumClouds()=0; };
Здравствуйте, rasp_file, Вы писали:
KA>>Что надо скормить компилятору, чтобы подобные конструкции заработали? KA>>Не хотелось бы вводить для этого интерфейс. _>конечно, вопрос из области теории но зачем так делать?
Я привёл упрощенный пример.
В реальной программе код чуток более наворочен и выглядит приблизительно так:
using System.Collections.Generic;
namespace EqualsTest
{
interface IBase
{
void Everything();
}
class Super : IBase
{
public void Everything() { }
public bool Equals(Super other) { return true; }
}
class Container<T> : List<T> where T: IBase
{
public bool Equals(Container<T> other)
{
if (Count != other.Count)
return false;
for (int i = 0; i < Count; ++i)
if (!this[i].Equals(other[i])) // always calls System.Object.Equals(Object)return false;
return false;
}
}
class Program
{
static void Main(string[] args)
{
Container<Super> con1 = new Container<Super>();
con1.Add(new Super());
Container<Super> con2 = new Container<Super>();
con2.Add(new Super());
System.Console.WriteLine("{0}", con1.Equals(con2));
}
}
}
Этот чудо-код компилируется, но всегда выдаёт False, поскольку всегда вызывается метод System.Object.Equals, который сравнивает значения ссылок.
Как этот фрагмент можно было бы переделать с учётом особенностей generics in C#?
_>generics реализованы не как templates в C++. грубо говоря никакой текстовой подстановки и инстанцирования нет.
Эх, ну, жаль, что подход шаблонов в стиле C++ не доступен в C#...
// #import <windows.bas> class IWindows9x:protected DOS { private: virtual HANDLE EnumClouds()=0; };
Хм. Спасибо за исправления, но меня не интересует сравнение через System.Object — мне придётся много методов переопределять.
В generic-контейнерах у меня хранятся определённые объекты, и я хочу сравнивать их с объектами того же типа.
Поэтому путь через переопределение стандартного метода Equals и GetHashCode — это слишком громоздко.
Есть ли способ попроще?
// #import <windows.bas> class IWindows9x:protected DOS { private: virtual HANDLE EnumClouds()=0; };
Здравствуйте, KA, Вы писали:
KA>Поэтому путь через переопределение стандартного метода Equals и GetHashCode — это слишком громоздко. KA>Есть ли способ попроще?
Есть, но о нём Вам уже говорили — class Container<T> : List<T> where T: Super. Либо интерфейс. Дженерики — это не шаблоны C++, совсем.
"Нормальные герои всегда идут в обход!"
Re[7]: Вызов "неизвестного" метода Equals из шаблона
Здравствуйте, Jolly Roger, Вы писали:
KA>>Поэтому путь через переопределение стандартного метода Equals и GetHashCode — это слишком громоздко. KA>>Есть ли способ попроще?
JR>Есть, но о нём Вам уже говорили — class Container<T> : List<T> where T: Super. Либо интерфейс. Дженерики — это не шаблоны C++, совсем.
Оказывается, метод попроще всё-таки есть.
Как верно подметили в этой теме ранее, он реализуется через интерфейс, вернее через стандартный generic-interface IEquatable<T>.
Ранее приведенный кусок кода надо дополнить всего парой строк (выделены жирным шрифтом), а именно:
using System.Collections.Generic;
namespace EqualsTest
{
interface IBase
{
void Everything();
}
class Super : IBase, System.IEquatable<Super>
{
public void Everything() { }
public bool Equals(Super other) { return true; }
}
class Container<T> : List<T> where T: IBase, System.IEquatable<T>
{
public bool Equals(Container<T> other)
{
if (Count != other.Count)
return false;
for (int i = 0; i < Count; ++i)
if (!this[i].Equals(other[i]))
return false;
return true;
}
}
class Program
{
static void Main(string[] args)
{
Container<Super> con1 = new Container<Super>();
con1.Add(new Super());
Container<Super> con2 = new Container<Super>();
con2.Add(new Super());
System.Console.WriteLine("{0}", con1.Equals(con2));
}
}
}
Всем спасибо за соучастие
// #import <windows.bas> class IWindows9x:protected DOS { private: virtual HANDLE EnumClouds()=0; };
Re[8]: Вызов "неизвестного" метода Equals из шаблона
Здравствуйте, KA, Вы писали:
KA>Оказывается, метод попроще всё-таки есть. KA>Как верно подметили в этой теме ранее, он реализуется через интерфейс, вернее через стандартный generic-interface IEquatable<T>.
JR>>Есть, но о нём Вам уже говорили — class Container<T> : List<T> where T: Super. Либо интерфейс.
"Нормальные герои всегда идут в обход!"
Re[9]: Вызов "неизвестного" метода Equals из шаблона
Здравствуйте, Jolly Roger, Вы писали:
KA>>Оказывается, метод попроще всё-таки есть. KA>>Как верно подметили в этой теме ранее, он реализуется через интерфейс, вернее через стандартный generic-interface IEquatable<T>.
JR>>>Есть, но о нём Вам уже говорили — class Container<T> : List<T> where T: Super. Либо интерфейс. JR>
миль пардон. Я, как начинающий в C#, не догадался, что вы имели в виду именно интерфейс IEquatable
// #import <windows.bas> class IWindows9x:protected DOS { private: virtual HANDLE EnumClouds()=0; };
Re[9]: Вызов "неизвестного" метода Equals из шаблона
Здравствуйте, HowardLovekraft, Вы писали:
KA>>Оказывается, метод попроще ... KA>> реализуется через интерфейс IEquatable<T>. KA>>Ранее приведенный кусок кода надо дополнить всего парой строк (выделены жирным шрифтом), а именно: KA>>
KA>> class Super : IBase, System.IEquatable<Super>
KA>> {
KA>> public void Everything() { }
KA>> public bool Equals(Super other) { return true; }
KA>> }
KA>>}
HL>До конца не дочитали? HL>
HL>Примечания для разработчиков
HL>Если реализуется интерфейс IEquatable<T>, следует также переопределить реализацию базового класса для методов Object.Equals(Object) и GetHashCode, чтобы их поведение соответствовало поведению метода IEquatable<T>.Equals.
HL>Для простых случаев проще использовать свой IEqualityComparer<IBase>
Эээ... спасибо за подсказку.
Хоть это и не следует из приведенного мною фрагмента кода, в моём случае идёт сравнение только однотипных объектов, т.е. я не собираюсь сравнивать Super с каким-то гипотетическим классом Super2, а только Super — c Super'ом, и Super2 — c Super2.
Если же пользователь захочет сравнивать через Equals(Object), то эту вредную наклонность проще пресечь сокрытием данного метода, или выбрасыванием исключения, ибо нефиг (это не имеет смысла в предметной области, которая моделируется программой).
EqualityComparer — интересный класс. Возможно, его применение и оправдано в более сложных случаях. Пока что я не вижу необходимости выносить сравнение из Super.Equals(Super) в EqualityComparer.Equals(Super,Super).
// #import <windows.bas> class IWindows9x:protected DOS { private: virtual HANDLE EnumClouds()=0; };
Re[10]: Вызов "неизвестного" метода Equals из шаблона