Почему нельзя '=' перегружать в C #? - PullRequest
18 голосов
/ 01 марта 2009

Мне было интересно, почему я не могу перегрузить '=' в C #? Могу ли я получить лучшее объяснение?

Ответы [ 12 ]

31 голосов
/ 01 марта 2009

Языки, управляемые памятью, обычно работают со ссылками, а не с объектами. Когда вы определяете класс и его члены, вы определяете поведение объекта, но когда вы создаете переменную, вы работаете со ссылками на эти объекты.

Теперь оператор = применяется к ссылкам, а не к объектам. Когда вы присваиваете ссылку на другую, вы фактически делаете принимающую опорную точку тем же объектом, что и другая ссылка.

Type var1 = new Type();
Type var2 = new Type();

var2 = var1;

В приведенном выше коде два объекта создаются в куче, один из которых указан как var1, а другой - как var2. Теперь последний оператор делает ссылку на var2 тем же объектом, на который ссылается var1. После этой строки сборщик мусора может освободить второй объект, и в памяти остается только один объект. Во всем процессе никакие операции не применяются к самим объектам.

Возвращаясь к тому, почему = невозможно перегрузить, реализация системы - единственная разумная вещь, которую вы можете сделать со ссылками. Вы можете перегрузить операции, которые применяются к объектам, но не к ссылкам.

16 голосов
/ 01 марта 2009

Если вы перегружаете '=', вы никогда не сможете изменить ссылку на объект после его создания. ... подумайте - любой вызов theObjectWithOverloadedOperator = что-то внутри перегруженного оператора приведет к другому вызову перегруженного оператора ... так что же на самом деле будет делать перегруженный оператор? Может быть, установить некоторые другие свойства - или установить значение для нового объекта (неизменяемость)? Как правило, не то, что '=' подразумевает ..

Однако вы можете переопределить неявные и явные операторы приведения: http://www.blackwasp.co.uk/CSharpConversionOverload.aspx

8 голосов
/ 01 марта 2009

Потому что на самом деле это не имеет смысла.

В C # = присваивает ссылку на объект переменной. Таким образом, он работает с переменными и ссылками на объекты, а не на сами объекты. Нет смысла перегружать его в зависимости от типа объекта.

В C ++ определение оператора = имеет смысл для классов, экземпляры которых могут быть созданы, например, в стеке, потому что сами объекты хранятся в переменных, а не в ссылках на них. Поэтому имеет смысл определить, как выполнить такое задание. Но даже в C ++, если у вас есть набор полиморфных классов, которые обычно используются с помощью указателей или ссылок, вы обычно явно запрещаете копировать их таким образом, объявляя operator = и копируя конструктор как private (или наследуя от boost :: noncopyable), из-за точно такие же причины, как почему вы не переопределяете = в C #. Проще говоря, если у вас есть ссылка или указатель класса A, вы на самом деле не знаете, указывает ли он на экземпляр класса A или класса B, который является подклассом A. Так вы действительно знаете, как выполнить = в этой ситуации?

6 голосов
/ 01 марта 2009

На самом деле, перегрузка operator = будет иметь смысл, если вы сможете определять классы со семантикой значений и размещать объекты этих классов в стеке . Но в C # вы не можете.

4 голосов
/ 01 марта 2009

Одним из возможных объяснений является то, что вы не можете делать правильные справочные обновления, если перегрузите оператор присваивания. Это буквально испортило бы семантику, потому что, когда люди ожидают обновления ссылок, ваш оператор = может также делать что-то еще полностью. Не очень дружелюбный к программисту.

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

3 голосов
/ 01 марта 2009

Вы можете перегрузить присваивание в C #. Только не на весь объект, а только на его членов. Вы объявляете свойство с помощью сеттера:

class Complex
{
    public double Real
    {
        get { ... }
        set { /* do something with value */ }
    }

    // more members
}

Теперь, когда вы присваиваете Real, запускается ваш собственный код.

Причина, по которой присвоение объекта не является заменяемым, состоит в том, что он уже определен языком как нечто жизненно важное.

3 голосов
/ 01 марта 2009

Я не думаю, что есть какая-то конкретная причина, на которую можно указать. Вообще, я думаю, что идея выглядит так:

  • Если ваш объект - большой, сложный объект, выполнение чего-то, что не назначено с помощью оператора =, вероятно, вводит в заблуждение.

  • Если ваш объект - маленький объект, вы также можете сделать его неизменным и возвращать новые копии при выполнении операций с ним, чтобы оператор присваивания работал так, как вы ожидаете, из коробки (как System.String делает.)

1 голос
/ 01 марта 2009

Потому что застрелить себя в ногу осуждают.

На более серьезной ноте можно только надеяться, что вы имели в виду сравнение, а не задание. Фреймворк содержит подробное положение о вмешательстве в оценку равенства / эквивалентности, ищите «сравнение» в справке или онлайн с msdn.

1 голос
/ 01 марта 2009

Это разрешено в C ++, и если не соблюдать осторожность, это может привести к путанице и поиску ошибок.

Эта статья объясняет это очень подробно.

http://www.relisoft.com/book/lang/project/14value.html

0 голосов
/ 26 декабря 2016

Тип переопределяющего назначения

Существует два типа переопределения назначения:

  1. Когда вы чувствуете, что пользователь может что-то упустить, и вы хотите, чтобы пользователь использовал «кастинг» как float to integer, когда вы теряете плавающее значение

int a = (int)5.4f;

  1. Когда вы хотите, чтобы пользователь сделал это, даже не заметив, что он / она меняет тип объекта

float f = 5;

Как переопределить назначение

Для 1 используйте ключевое слово explicit:

public static explicit override ToType(FromType from){
    ToType to = new ToType();
    to.FillFrom(from);
    return to;
}

Для 2 используйте ключевое слово implicit:

public static implicit override ToType(FromType from){
    ToType to = new ToType();
    to.FillFrom(from);
    return to;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...