Есть ли способ перегрузки оператора присваивания в С#?

В отличие от С++, в С# вы не можете перегрузить оператор присваивания.

Я делаю собственный класс Number для арифметических операций с очень большими числами, и я хочу, чтобы у него были вид встроенных числовых типов, таких как int, decimal и т.д. Я перегрузил арифметику операторов, но присваивание остается...

Вот пример:

Number a = new Number(55); 
Number b = a; //I want to copy the value, not the reference

Есть ли обходной путь для этой проблемы?

Ответ 1

Мне все еще не ясно, что вам это действительно нужно. Или:

  • Тип вашего номера должен быть структурой (что является вероятным - номера являются наиболее распространенным примером структур). Обратите внимание, что все типы, к которым вы хотите, чтобы ваш тип работал как (int, decimal и т.д.), Являются структурами.

или

  • Тип вашего номера должен быть неизменным, заставляя каждую операцию мутации возвращать новый экземпляр, и в этом случае вам не нужны данные, которые нужно копировать при назначении. (На самом деле, ваш тип должен быть неизменным, независимо от того, является ли он структурой. Переменные структуры являются злыми, а число, конечно же, не должно быть изменчивым ссылочным типом.)

Ответ 2

вы можете использовать ключевое слово 'implicit' для создания перегрузки для назначения:

Предположим, что у вас есть такой тип, как Foo, который, по вашему мнению, неявно конвертируется из строки. Вы должны написать следующий статический метод в своем классе Foo:

public static implicit operator Foo(string normalString)
{
    //write your code here to go from string to Foo and return the new Foo.
}

Сделав это, вы можете использовать в своем коде следующее:

Foo x = "whatever";

Ответ 3

Вы не сможете обойти это, имея вид С++, поскольку a = b; имеет другую семантику в С++, чем в С#. В С# a = b; указывает точку на тот же объект, что и b. В С++ a = b изменяет содержимое a. У обоих есть свои взлеты и падения. Это как вы.

MyType * a = new MyType();
MyType * b = new MyType(); 
a = b; /* only exchange pointers. will not change any content */

В С++ (он потеряет ссылку на первый объект и создаст утечку памяти, но пусть игнорирует это здесь). Вы также не можете перегрузить оператор присваивания в С++.

Обходной путь прост:

MyType a = new MyType();
MyType b = new MyType();

// instead of a = b
a.Assign(b);

Отказ от ответственности: я не разработчик С#

Вы можете создать свойство write-only, подобное этому. затем выполните a.Self = b; выше.

public MyType Self {
    set {
        /* copy content of value to this */
        this.Assign(value);
    }
}

Теперь это не хорошо. Поскольку это нарушает принцип наименьшего удивления (POLS). Нельзя ожидать, что изменится, если вы сделаете a.Self = b;

Ответ 4

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

Операции, которые изменят данные, будут, конечно, возвращать новые экземпляры.

Ответ 5

Раннее сообщение предложило следующее:

открытый статический неявный оператор Foo (строка normalString) {}

Я пробовал этот подход... но чтобы он работал, вам это нужно:

открытый статический неявный оператор Foo (Foo original) {}

и компилятор не позволит вам иметь функцию неявного преобразования от вашего точного типа, а также от любого базового типа. Это имеет смысл, поскольку это было бы бэкдорным способом переопределения оператора присваивания, который С# не хочет разрешать.

Ответ 6

Вот решение, которое сработало для меня:

public class MyTestClass
{
   private int a;
   private string str;

   public MyTestClass()
   {
      a = 0;
      str = null;
   }

   public MyTestClass(int a, string str)
   {
      this.a = a;
      this.str = str;
   }

   public MyTestClass Clone
   {
      get
      {
         return new MyTestClass(this.a, this.str);
      }
   }
}

Где-то еще в коде:

MyTestClass test1 = new MyTestClass(5, "Cat");
MyTestClass test2 = test1.Clone;