Есть ли обходной путь для перегрузки оператора присваивания в C #? - PullRequest
32 голосов
/ 15 ноября 2008

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

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

Вот пример:

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

Есть ли решение этой проблемы?

Ответы [ 7 ]

42 голосов
/ 05 февраля 2009

вы можете использовать ключевое слово '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";
28 голосов
/ 15 ноября 2008

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

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

или

  • Ваш тип Number должен быть неизменным, чтобы каждая операция мутации возвращала новый экземпляр, и в этом случае вам все равно не нужно копировать данные при назначении. (На самом деле, ваш тип должен быть неизменным, независимо от того, является ли он структурой. Изменяемые структуры - это зло, и число определенно не должно быть изменяемым ссылочным типом.)
6 голосов
/ 15 ноября 2008

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

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

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

Обойти это легко:

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

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

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

Вы можете создать свойство только для записи, как это. тогда сделайте a.Self = b; выше.

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

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

3 голосов
/ 15 ноября 2008

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

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

2 голосов
/ 06 января 2011

Более ранний пост предложил это:

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

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

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

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

0 голосов
/ 10 октября 2016

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

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;
0 голосов
/ 07 сентября 2012

Может быть, то, что вы ищете, можно решить с помощью средств доступа C #.

http://msdn.microsoft.com/en-us/library/aa287786(v=vs.71).aspx

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...