Есть ли обходной путь для перегрузки оператора присваивания в C#?
В отличие от C++, в C# вы не можете перегружать оператор присваивания.
Я делаю пользовательский класс Number для арифметических операций с очень большими числами, и я хочу, чтобы он имел внешний вид встроенных числовых типов, таких как int, decimal и т. Д. Я перегружен арифметическими операторами, но назначение остается...
Вот пример:
Number a = new Number(55);
Number b = a; //I want to copy the value, not the reference
Есть ли решение этой проблемы?
7 ответов
Мне все еще не совсем ясно, что тебе это действительно нужно. Или:
- Ваш тип Number должен быть структурой (что вероятно - числа являются наиболее распространенным примером структур). Обратите внимание, что все типы, которые вы хотите, чтобы ваш тип действовал как (int, decimal и т. Д.), Являются структурами.
или же:
- Ваш тип Number должен быть неизменным, чтобы каждая операция мутации возвращала новый экземпляр, и в этом случае вам все равно не нужно копировать данные при назначении. (На самом деле, ваш тип должен быть неизменным, независимо от того, является ли он структурой. Изменяемые структуры - это зло, и число определенно не должно быть изменяемым ссылочным типом.)
Вы можете использовать ключевое слово '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";
Вы не сможете обойти это, имея внешний вид 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;
Вместо того чтобы делать копию данных при передаче ссылки, вы можете сделать класс неизменным. Когда класс является неизменным, наличие нескольких ссылок на него не является проблемой, поскольку его нельзя изменить.
Операции, которые изменяют данные, будут, конечно, возвращать новые экземпляры.
Более ранний пост предложил это:
открытый статический неявный оператор Foo(string normalString) { }
Я попробовал этот подход... но чтобы он работал, вам нужно это:
открытый статический неявный оператор Foo(Foo original) { }
и компилятор не позволит вам иметь неявную функцию преобразования из вашего точного типа или из любого базового типа себя. Это имеет смысл, поскольку это будет закулисный способ переопределения оператора присваивания, который C# не хочет разрешать.
Вот решение, которое сработало для меня:
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;
Возможно, то, что вы ищете, может быть решено с помощью средств доступа C#.
http://msdn.microsoft.com/en-us/library/aa287786(v=vs.71).aspx