Взглянул я тут на код StructuralEquality. Он дремучий и кривой. Данный макрос не реализует метод GetHashCode и всегда используется код "x.GetType().Equals(this.GetType())", что замедляет реализацию (особенно для структур).
Кроме того этот макрос не реализует интерфейсы IEquatable[T] и IStructuralEquatable.
Предлагаю кому-нибудь взяться за реализацию новой версии данного макроса, или даже лучше ряда макросов предоставляющую реализацию эквивалентности "из коробки".
Требования к новой реализации макроса:
1. Реализация интерфейсов IEquatable[T] и IStructuralEquatable.
2. Реализация методов Equals (типизированной) и GetHashCode.
3. Реализация макро-атрибута IgnoreInEquals (имя можно подобрать и получше).
4. Предоставление замены для "x.GetType().Equals(this.GetType())". Для структур этот код вообще не должен появляться, для класса должна быть настройка позволяющая опустить эту проверку. Кроме того такая проверка должна устраняться, если класс помечен модификатором sealed.
Кроме того предлагаю так же реализовать макрос реализующий IEqualityComparer[T] для заданного типа. Применять его так же имеет смысл к классу, но это будет класс компаратора. Сравниваемый же тип должен передаваться макросу в качестве параметра. Как вариант, можно реализовать макро-атрибут уровня сборки.
[ImplementIEqualityComparer(MyType)]
class MyTypeEqualityComparer { }
// или
[assembly: ImplementIEqualityComparer(MyType)]
Задача не сложная, но интересная.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
VD>Кроме того предлагаю так же реализовать макрос реализующий IEqualityComparer[T] для заданного типа. Применять его так же имеет смысл к классу, но это будет класс компаратора.
А почему не к классу, для которого нужен Comparer? А для случаев когда это нгевозможно, может быть макрос уровня сборки.
Здравствуйте, VladD2, Вы писали:
VD>Предлагаю кому-нибудь взяться за реализацию новой версии данного макроса, или даже лучше ряда макросов предоставляющую реализацию эквивалентности "из коробки".
Умеет:
1. Реализация интерфейса IEquatable[T].
2. Реализация методов Equals (типизированной) и GetHashCode.
3. Реализация макро-атрибута EqualsIgnore и опции Ignore в макросе.
4. Код "x.GetType().Equals(this.GetType())" отключается для структур, sealed-классов и опцией.
Не умеет:
1. Отключать проверку для автосвойств и автособытий
2. Поддерживать IStructuralEquatable (нету VS2010 чтобы потестить)
3. Ну, и еще код там местами потенциально N^2
Здравствуйте, catbert, Вы писали:
C>2. Поддерживать IStructuralEquatable (нету VS2010 чтобы потестить)
Сам VS2010 не нужен чтобы компилировать для .Net 4.0
Здравствуйте, catbert, Вы писали:
VD>>Предлагаю кому-нибудь взяться за реализацию новой версии данного макроса, или даже лучше ряда макросов предоставляющую реализацию эквивалентности "из коробки".
C>Альфа-версия макроса StructuralEquality2:
C>http://files.rsdn.ru/92155/StructuralEquality2.zip
Э... а зачем так сложно то?
Надо было просто сделать свой форк и работать в нем. Все кому интересно могли бы клонировать его и посмореть. Если будет все ОК, то можно будет сделать pull-request и залить изменения одним нажатием.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Для простых встроенных типов нужно избегать использования вызовов GetHashCode и Equals.
И, нельзя ли избавиться от умножений при расчете хэш-кодов? Это весьма тяжелые операции. Не думаю, что это реально даст хоть что-то для уменьшения колизий.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
VD>Здравствуйте, catbert, Вы писали:
C>>Умеет: C>>3. Реализация ... и опции Ignore в макросе.
VD>Вот это, по-моему, лишнее. Атрибут по жизни удобнее.
Я делал по аналогии с Record, там есть и опция и атрибут.
C>>4. Код "x.GetType().Equals(this.GetType())" отключается для структур, sealed-классов и опцией.
VD>Здорово!
VD>А в чем глубинный смысл этого кода: VD>
Это я содрал со старой реализации. Оно проверяет на null. Очевидно, стоит заменить на .?
VD>Это не хорошо. Макры, особенно такие часто используемые могут сильно замедлить компиляцию. VD>Тут лучше не писать заведомо медленный код.
Тут просто не факт, что код с лучшей асимптотичной сложностью будет в среднем быстрее. Надо еще измерения провести
C>>Не умеет: C>>1. Отключать проверку для автосвойств и автособытий
VD>Почему?
Потому что в Немерле:
1) из автосвойств и автособытий нельзя вытащить сгенерированное поле
2) странно работает (или вообще не работает — я так и не понял) навешивание аттрибутов и макросов на сгенерированные автосвойствами поля.
В результате, нельзя узнать, какое поле отвечает какому свойству.
Здравствуйте, hardcase, Вы писали:
H>Здравствуйте, catbert, Вы писали:
C>>Альфа-версия макроса StructuralEquality2:
C>>http://files.rsdn.ru/92155/StructuralEquality2.zip
H>На гитхабе было бы как-то удобнее, чтоли...
Здравствуйте, catbert, Вы писали:
C>Я делал по аналогии с Record, там есть и опция и атрибут.
Да это наследие былых времен. С появлением RecordIgnor, лично я стал пользоваться только им.
C>Тут просто не факт, что код с лучшей асимптотичной сложностью будет в среднем быстрее. Надо еще измерения провести
Что там тестировать? Если возможен квадрат, то он нарисуется. Это закон Мерфи.
C>>>Не умеет: C>>>1. Отключать проверку для автосвойств и автособытий
VD>>Почему?
C>Потому что в Немерле: C>1) из автосвойств и автособытий нельзя вытащить сгенерированное поле
Да ладно. Они доступны без проблем. И твой код их подхватывает. Вот декомпилированный код:
// Program.Simple
[CompilerGenerated]
public override int GetHashCode()
{
int num = 842801;
num = 700127 * num + EqualityComparer<string>.Default.GetHashCode(this.First);
num = 700127 * num + this.Second.GetHashCode();
return 700127 * num + this._N_Third_3603.GetHashCode();
}
C>2) странно работает (или вообще не работает — я так и не понял) навешивание аттрибутов и макросов на сгенерированные автосвойствами поля.
Это другой вопрос. Хардкейс говорил, что навешивание атрибутов должно работать. Но может он ошибался. Надо проверять.
C>В результате, нельзя узнать, какое поле отвечает какому свойству.
Это вообще можно узнать из описания свойства. У PropertyBuilder есть свойство AutoPropertyField. В него должна помещаться ссылка на соответствующее поле.
Кроме того в макросе Record игнорирование для автосвойств работает. Так что проблем быть не должно.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
VD>Здравствуйте, catbert, Вы писали:
VD>Для простых встроенных типов нужно избегать использования вызовов GetHashCode и Equals.
Почему? И как?
VD>И, нельзя ли избавиться от умножений при расчете хэш-кодов? Это весьма тяжелые операции. Не думаю, что это реально даст хоть что-то для уменьшения колизий.
Можно В этом списке, например, есть и хеши с одними шифтами:
Здравствуйте, VladD2, Вы писали:
C>>Потому что в Немерле: C>>1) из автосвойств и автособытий нельзя вытащить сгенерированное поле
VD>Да ладно. Они доступны без проблем. И твой код их подхватывает. Вот декомпилированный код:
Да, но соответствия с полями нету.
VD>Это вообще можно узнать из описания свойства. У PropertyBuilder есть свойство AutoPropertyField. В него должна помещаться ссылка на соответствующее поле.
Этого я не находил. Буду глядеть.
VD>Кроме того в макросе Record игнорирование для автосвойств работает. Так что проблем быть не должно.
Оно самым наглым образом захардкожено в MainParser.n
Здравствуйте, VladD2, Вы писали:
VD>Здравствуйте, catbert, Вы писали:
VD>Для простых встроенных типов нужно избегать использования вызовов GetHashCode и Equals.
VD>И, нельзя ли избавиться от умножений при расчете хэш-кодов? Это весьма тяжелые операции. Не думаю, что это реально даст хоть что-то для уменьшения колизий.
Я делал хэширование по аналогии с хэшированием, которое генерирует C# компилятор для GetHashCode у анонимных типов.
Здравствуйте, catbert, Вы писали:
VD>>Это вообще можно узнать из описания свойства. У PropertyBuilder есть свойство AutoPropertyField. В него должна помещаться ссылка на соответствующее поле.
C>Этого я не находил. Буду глядеть.
VD>>Кроме того в макросе Record игнорирование для автосвойств работает. Так что проблем быть не должно.
C>Оно самым наглым образом захардкожено в MainParser.n
В смысле?
И чем не подходит AutoPropertyField?
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, catbert, Вы писали:
VD>>Для простых встроенных типов нужно избегать использования вызовов GetHashCode и Equals.
C>Почему? И как?
Вместо Equals использовать ==. Вместо хэш-кода само значение (для int) или несложные манипуляции с ним (их можно подсмотреть в Рефлекторе). Это будет в сто раз быстрее чем виртуальные вызовы.
VD>>И, нельзя ли избавиться от умножений при расчете хэш-кодов? Это весьма тяжелые операции. Не думаю, что это реально даст хоть что-то для уменьшения колизий.
C>Можно В этом списке, например, есть и хеши с одними шифтами:
C>http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx
Ну, вот хорошо бы вынести хэш-алгоритм в настройки и предоставить по возможность выбирать между быстрым и более хитрым алгоритмом. По умолчанию использовать быстрый (на базе ^ и <<), а если кому-то захочется, то использовать более хитрый. Можно даже позволять свой шаблон расчета хэш-значений задавать.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, catbert, Вы писали:
VD>>Это вообще можно узнать из описания свойства. У PropertyBuilder есть свойство AutoPropertyField. В него должна помещаться ссылка на соответствующее поле.
C>Этого я не находил. Буду глядеть.
Что там глядеть то? Там все просто.
VD>>Кроме того в макросе Record игнорирование для автосвойств работает. Так что проблем быть не должно.
C>Оно самым наглым образом захардкожено в MainParser.n
Это гдейто?
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Умеет:
1. Реализация интерфейсов IEquatable[T] и IStructuralEquatable.
2. Реализация методов Equals (типизированной) и GetHashCode.
3. Реализация макро-атрибута EqualsIgnore и опции Ignore в макросе.
4. Код "x.GetType().Equals(this.GetType())" отключается для структур, sealed-классов и опцией.
5. Отключать проверку для автосвойств
Не умеет:
1. Отключать проверку для автособытий
2. Реализовать интерфейсы для Nemerle.Builtins.Tuple (Немерле перестает собираться)