Есть ли у кого-нибудь мнения о том, требуется ли вообще IEquatable<T> или IComparable<T>, чтобы T был sealed (если он a class)?
Этот вопрос возник со мной, так как я пишу набор базовых классов, предназначенных для помощи в реализации неизменяемых классов. Часть функциональности, которую должен обеспечить базовый класс, - автоматическая реализация сравнений равенства (с использованием полей класса вместе с атрибутами, которые могут применяться к полям для контроля сравнений равенства). Это должно быть довольно хорошо, когда я закончен - я использую деревья выражений для динамического создания скомпилированной функции сравнения для каждого T, поэтому функция сравнения должна быть очень близка к производительности регулярной функции сравнения равенства. (Я использую неизменяемый словарь с ключом System.Type и дважды проверяю блокировку, чтобы хранить сгенерированные функции сравнения так, чтобы это было разумно выполнено)
Однако одна вещь, которая возникла, - это то, какие функции использовать для проверки равенства полей-членов. Мое первоначальное намерение состояло в том, чтобы проверить, реализует ли тип поля каждого члена (который я назовем X) IEquatable<X>. Однако, подумав, я не думаю, что это безопасно использовать, если X не является sealed. Причина в том, что если X не sealed, я не уверен, что если X надлежащим образом делегирует проверки равенства виртуальному методу на X, тем самым позволяя подтипу переопределить сравнение равенства.
В этом случае возникает более общий вопрос: если тип не запечатан, должен ли он действительно реализовать эти интерфейсы НА ВСЕ? Я бы не подумал, так как я бы сказал, что контракт с интерфейсом заключается в сравнении двух типов X, а не двух типов, которые могут быть или не быть X (хотя они должны быть, конечно, X или подтипом).
Что вы, ребята, думаете? Следует ли избегать IEquatable<T> и IComparable<T> для незапечатанных классов? (Также заставляет задуматься, есть ли для этого правило fxcop)
Моя текущая мысль заключается в том, чтобы моя сгенерированная функция сравнения использовала только IEquatable<T> в полях-членах, T - sealed, а вместо этого использовать виртуальный Object.Equals(Object obj), если T не распечатано, даже если T реализует IEquatable<T>, так как поле может потенциально хранить подтипы T, и я сомневаюсь, что большинство реализаций IEquatable<T> спроектированы надлежащим образом для наследования.