Когда два перечисления равны в С#?

Я создал два перечисления, и я знаю, что они одинаковы, но все же я думаю, что имеет смысл, что они будут равны, поскольку их строковое представление, а также их числовое представление равны (и даже то же самое...).

Другими словами: я хотел бы, чтобы первый тест прошел, а второй не прошел. Однако на самом деле они оба терпят неудачу. Итак: когда два перечисления в С# равны? Или в любом случае определить оператор равенства в С#?

Спасибо!

    public enum enumA {one, two}

    public enum enumB {one, two}

    [Test]
    public void PreTest()
    {           
    Assert.AreEqual(enumA.one,enumB.one);
    Assert.AreSame(enumA.one, enumB.one);
    }

ОБНОВЛЕНИЕ: 1) Итак, все ответы до сих пор сравнивают представления, будь то целые числа или строки. Как я понимаю, перечисление само всегда неравно? Нет средств определить для него равенство?


person Peter    schedule 05.11.2009    source источник
comment
Дубликат: stackoverflow.com/questions/1410131/   -  person Robert Harvey    schedule 06.11.2009
comment
@Robert: спасибо за ссылку, интересную и связанную. Явно не дубликат: он запрашивает значение перечисления.   -  person Peter    schedule 06.11.2009


Ответы (6)


Перечисления строго типизированы в C#, поэтому enumA.one != enumB.one. Теперь, если бы вы преобразовали каждое перечисление в их целочисленное значение, они были бы равны.

Assert.AreEqual((int)enumA.one, (int)enumB.one);

Кроме того, я хотел бы оспорить утверждение, что, поскольку они имеют одинаковое целочисленное или строковое представление, они должны быть одинаковыми или равными. Учитывая два перечисления NetworkInterface и VehicleType, для C# или .Net Framework было бы нелогично допускать, чтобы NetworkInterface.None равнялось VehicleType.None при сравнении как перечисление либо по значению, либо по строке. Однако, если разработчик привел строго типизированное перечисление к целому числу или строке, язык или инфраструктура ничего не могут сделать, чтобы помешать им быть равными.

Чтобы уточнить, вы не можете переопределить MyEnum.Equals, чтобы предоставить другой метод равенства. Перечисления .Net не совсем первоклассные граждане, как в более поздних версиях Java, и я бы хотел, чтобы C# допускал более богатые взаимодействия с перечислениями.

person user7116    schedule 05.11.2009
comment
будьте осторожны, это верно только в том случае, если порядковый номер одинаков. - person Tim Jarvis; 06.11.2009
comment
Спасибо. Но оператор != НЕ тот, который я использую, скорее, equals(). Я думал, что даже разные строго типизированные типы могут быть равны, или это не так? - person Peter; 06.11.2009
comment
@Peter: перечисления - это структуры, более того, вы не можете перегружать ни один из их методов. Также я использовал != скорее как глагол, чем как фактический фрагмент кода. @ Тим: действительно, это для его случая и только для него. - person user7116; 06.11.2009
comment
Перечисления - это типы значений, чтобы прояснить мое выше. - person user7116; 06.11.2009
comment
Жаль, что MS использовала то же имя для виртуального метода Equals(Object), что и для перегрузок, зависящих от типа; все было бы намного яснее, если бы первых назвали EquivalentTo. Как бы то ни было, Equals определяет отношение эквивалентности только в том случае, если операнд приводится к Object. В противном случае (4.0).Equals(4.0f) истинно [4.0f преобразуется и сравнивается с double], но (4.0f).Equals(4.0) ложно [4.0 преобразуется и сравнивается с Object ]. Аналогичные ситуации применяются при сравнении типов перечисления и целых чисел. - person supercat; 21.03.2013
comment
Если бы виртуальный метод был назван EquivalentTo, то если бы X и Y были числовыми или перечислимыми переменными со значением четыре, то можно было бы ожидать, что X.Equals(Y) выдаст значение true, когда приведение типов позволит осмысленное сравнение, и откажется от компиляции, если это не так; Между тем от X.EquivalentTo(Y) ожидается гораздо более строгое сравнение [такое, что (4.0).EquivalentTo(4.0f) или даже (4.0m).EquivalentTo(4.00m) вернет false. Однако уже немного поздно для MS, чтобы изменить это. - person supercat; 21.03.2013

Я отсылаю вас к C# Language Specification v3.0, из которого эта цитата была извлечена из раздела Enum на стр. 29:

«Каждый тип перечисления имеет соответствующий интегральный тип, называемый базовым типом типа перечисления. Тип перечисления, который явно не объявляет базовый тип, имеет базовый тип int. Формат хранения типа перечисления и диапазон возможных значений определяются его базовый тип. Набор значений, которые может принимать тип перечисления, не ограничен его элементами перечисления. В частности, любое значение базового типа перечисления может быть приведено к типу перечисления и является отдельным допустимым значением этого перечисления. тип."

Метод .AreEqual действительно проверяет эквивалентность, в то время как второй проверяет идентичность. Итак, просто приведите каждый к его базовому типу (в данном случае int), а затем выполните сравнение.

public enum enumA { one, two }
public enum enumB { one, two }
[Test]
public void PreTest()
{
        Assert.AreEqual((int)enumA.one,(int)enumB.one);
        Assert.AreSame(enumA.one, enumB.one);
}
person cpkilekofp    schedule 05.11.2009

В отличие от Java, C# не предоставляет никаких средств для добавления методов (таких как operator==()) в перечисление.

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

public static bool EnumAHelper.EqualsEnumB(EnumA enumA, EnumB enumB)
{
    return (int)enumA == (int)enumB;
}

Хотя я не припоминаю, чтобы мне приходилось сталкиваться с двумя разными перечислениями для обозначения одного и того же.

person Jeffrey L Whitledge    schedule 05.11.2009
comment
Очень хорошее замечание (хотя и после). Я переписываю существующий класс, который хочу сделать совместимым, поэтому его перечисления тоже должны быть одинаковыми. - person Peter; 06.11.2009

Если вы хотите, чтобы они совпадали, приведите их к int

Assert.AreEqual((int)enumA.one,(int)enumB.one);

пройдет, потому что они оба первые в списке. Если вы хотите, чтобы они совпадали, потому что они оба говорят «один», вам нужно использовать отражение.

person Lou Franco    schedule 05.11.2009
comment
Я думаю, вы могли бы сделать это, чтобы проверить строковые значения: Assert.AreEqual(enumA.one.ToString(), enumB.one.ToString()); - person Jonas; 06.11.2009

Честно говоря, Равенство в большинстве случаев не прямолинейно.

Я был бы склонен создать вспомогательный класс, который реализует IEqualityComparer (и любые другие тесты на равенство, например, IsSame()) и использовать его.

person Tim Jarvis    schedule 05.11.2009

Вы можете попробовать бросить их:

Assert.AreEqual((int)enumA.one, (int)enumB.one);
person Jonas    schedule 05.11.2009