|
operator ==, IEquatable<T>.Equals(T), Object.Equals(object, object)
|
|||
---|---|---|---|
#18+
Для того, чтоб сравнить 2 значения, в C# есть 3 способа (на сколько я знаю) А) Сравнить значения через оператор == Б) Через метод IEquatable<T>.Equals(T value) В) Через метод Equals(object, object) или Equals(object) который определен в классе Object (разницы между ними делать не буду, по факту оба варианта получают в качестве аргумента 2 значения и сравнивают их, отличие только в доп. проверке на null в 1 варианте) У каждого метода есть свои плюсы и минусы, уверен, что многих плюсов и минусов я не знаю или забуду упомянуть и надеюсь на вашу бдительность и ваши знания. А) + Простота использования + Высокая скорость работы, если посмотреть получившийся исполняемый код, то при сравнении значений для простых числовых типов, сравнение осуществляется оператором cmp, если сравнивать 2 разных типа, то к сравнению еще прибавляется неявное преобразование типа. - Оператор может вводить в заблуждение неопытных программистов, так как непонятно как именно осуществляется проверка, по значению или по ссылке. Для классов где оператор явно не переопределен проверяется по ссылке, для структур по значению. То есть я должен знать заранее, определен там оператор явно или или нет, структура это или класс и т.д. - чтоб сравнить 2а разных типа, нужно быть уверенным в том, что хотя бы 1 из них неявно преобразовывается во 2ой (к счастью такие ошибки видны даже до компиляции) Б) Метод работает только с простыми типа или с типами которые наследуют интерфейс IEquatable. Для простых типов, это фактически пункт А, просто обёрнутый в отдельный вызов метода. + Значение передается без упаковки, заданного типа. + Высокая скорость работы - Косяк у данного способа в том, что если T это класс и 0ой аргумент не определен (аргумент this равен null), то метод нельзя будет вызвать и мы получим NullReferenceException. Если мне необходимо сравнить значение простого типа (класса, пусть будет string) с константой, то безопаснее будет написать примерно так Код: c# 1.
, а не наоборот, так как если переменная strVariable равна null, будут проблемы В) + Метод удобен тем, что работает всегда, не важно какой из аргументов может быть null + можно сравнить 2 значения разных типов. При условии, что метод object.Equals(object) переопределен и поддерживает сравнение с другим типом (плюс сомнительный) - Если они оба null мы получим True (что на мой взгляд бредово, как 2а неопределенных значения могут быть равными, ведь они не определены? %), фактически они могут даже представлять разные типы. Если мы сравним (object)null и (string)null мы получаем true. - Значения передаются через тип Object, а значит будут упакованы - Самый медленный вариант проверил на скорость, на сравнение 1000000000 значений типа int Для DEBUG x64 А) 00:00:03.4353033 Б) 00:00:04.2280944 В) 00:00:13.8591103 Для RELEASE x64 с оптимизацией A) 00:00:00.9026884 Б) 00:00:01.0187077 В) 00:00:10.9358837 Видно, что после оптимизации, вариант А, практически эквивалентен по скорости варианту Б. Что не может не радовать. Уверен, что мои знания вполне поверхностные и я чего то не учёл в данной теме, для этого я её и создал, вы и так всё это знаете, но может быть знаете больше и надеюсь добавите варианты и плюсы\минусы этих вариантов. Какой из методов вы выбираете и в каких случаях. ... |
|||
:
Нравится:
Не нравится:
|
|||
05.12.2017, 18:52 |
|
operator ==, IEquatable<T>.Equals(T), Object.Equals(object, object)
|
|||
---|---|---|---|
#18+
Roman Mejtes, Для размышлений: 1. C# Код: c# 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59. 60. 61. 62. 63. 64. 65. 66. 67. 68. 69. 70. 71. 72. 73. 74. 75. 76.
2. IL Код: c# 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59. 60. 61. 62. 63. 64. 65. 66. 67. 68. 69. 70. 71. 72. 73. 74. 75. 76. 77. 78. 79. 80. 81. 82. 83. 84. 85. 86. 87. 88. 89. 90. 91. 92. 93. 94. 95. 96. 97. 98. 99. 100. 101. 102. 103. 104. 105. 106. 107. 108. 109. 110. 111. 112. 113. 114. 115. 116. 117. 118. 119. 120. 121. 122. 123. 124. 125. 126. 127. 128. 129. 130. 131. 132.
... |
|||
:
Нравится:
Не нравится:
|
|||
06.12.2017, 06:54 |
|
operator ==, IEquatable<T>.Equals(T), Object.Equals(object, object)
|
|||
---|---|---|---|
#18+
Ну, и пояснения к вышеприведенному. 1. В случае int и Bar сравнение проверяется через ==, перегруженных опреторов равенства нет - в IL-код используется инструкция сeq . При этом для сравнения Bar решарпер выдает предупреждение "Possible unintended reference comparision; to get a value comparision, use Equals method". При добавлении в Bar операторов равенства предупреждение пропадает. 2. В случае Foo и Type сравнение проверяется через ==, и обатипа имеют перегруженные операторы равенства/неравенства. В данном случае в IL-коде уже используется не ceq, а вызов op_Equality - перегруженного оператора равенства. 3. В случае char используется проверка через char.Equals - реализацию IEquatable<T>. Реализация выглядит так : Код: c# 1. 2. 3. 4.
И обратите внимание, что при этом имеются перегруженные Equals(object) и GetHashCode() - это не частный случай char, а общее правило : If you implement IEquatable<T>, you should also override the base class implementations of Object.Equals(Object) and GetHashCode so that their behavior is consistent with that of the IEquatable<T>.Equals method. If you do override Object.Equals(Object), your overridden implementation is also called in calls to the static Equals(System.Object, System.Object) method on your class. In addition, you should overload the op_Equality and op_Inequality operators. This ensures that all tests for equality return consistent results. И из последнего пункта понятно, почему IEquatable<T>.Equals быстрее, чем object.Equals - он быстрее именно в случае value-типов за счет избавления от боксинга-анбоксинга (value-типы, завернутые в генерик-параметр, боксинга-анбоксинга не требуют). Что же до того, что сравнение интов через == работает чуть быстрее, чем через int.Equals - есть подозрение, что там используется какое-то сравнение, зашитое глубоко внутрь CLR, и специфичное именно для примитивных типов. Резюме. 1. Для примитивных типов вполне можно использовать операцию ==. Для значимых типов в общем случае - T.Equals(T). Наличие переопределенного оператора == роли не играет, т.к. его реализация будет осуществляться за счет всё тех же == и Equals внутри логики оператора - за редким исключением типа того же Type, у которого оператор сравнения выглядит так : Код: c# 1. 2. 3. 4. 5.
2. Для ссылочных типов разница между ==, T.Equals(T) и object.Equals(object) может быть только за счет отсутствия приведения типа - я сомневаюсь, что это съест много ресурсов. И оператор == к ним можно применять только в случае уверенности наличия перегруженного оператора равенства - иначе можно нарваться на сравнение ссылок. ... |
|||
:
Нравится:
Не нравится:
|
|||
06.12.2017, 06:54 |
|
operator ==, IEquatable<T>.Equals(T), Object.Equals(object, object)
|
|||
---|---|---|---|
#18+
Roman Mejtes, 1. Два КАКИХ значения? Значимых или ссылочных? 2. Операторы можно перегружать. 3. Equals может использовать типизированную реализацию IEquatabl 4. Сравнивать можно ещё и через IComparable 5. https://msdn.microsoft.com/ru-ru/library/ms224763(v=vs.110).aspx ... |
|||
:
Нравится:
Не нравится:
|
|||
06.12.2017, 10:21 |
|
operator ==, IEquatable<T>.Equals(T), Object.Equals(object, object)
|
|||
---|---|---|---|
#18+
Сон Веры Павловныможет быть только за счет отсутствия приведения типа В Equals всё равно будут сравниваться типы. ... |
|||
:
Нравится:
Не нравится:
|
|||
06.12.2017, 10:23 |
|
operator ==, IEquatable<T>.Equals(T), Object.Equals(object, object)
|
|||
---|---|---|---|
#18+
Roman MejtesДля того, чтоб сравнить 2 значения, в C# есть 3 способа (на сколько я знаю) А) Сравнить значения через оператор == Б) Через метод IEquatable<T>.Equals(T value) В) Через метод Equals(object, object) или Equals(object) который определен в классе Object Г) EqualityComparer<T>.Default.Equals(a, b) ... |
|||
:
Нравится:
Не нравится:
|
|||
06.12.2017, 10:51 |
|
|
start [/forum/topic.php?fid=20&fpage=36&tid=1399581]: |
0ms |
get settings: |
9ms |
get forum list: |
12ms |
check forum access: |
4ms |
check topic access: |
4ms |
track hit: |
75ms |
get topic data: |
11ms |
get forum data: |
2ms |
get page messages: |
67ms |
get tp. blocked users: |
2ms |
others: | 363ms |
total: | 549ms |
0 / 0 |