Перегрузка префиксного и постфиксного операторов в C#
Следующий код имеет проблему во время выполнения с непредвиденными ссылками, сделанными назначением инструкции приращения постфикса / префикса, как показано в коде ниже. Также может кто-нибудь предложить мне способ обработки объектов как типов значений в C#, как это предлагается ниже, если таковые имеются?
Я считаю, что код хорошо документирован с комментариями, разъясняющими каждое важное состояние. Не стесняйтесь задавать любые вопросы, касающиеся уточнения кода или имеющейся проблемы.
Заранее спасибо.
class Test {
public int x;
public Test(int x) { this.x=x; }
public Test() { x=0; }
static public Test operator++(Test obj) {
return new Test(obj.x+1);
}
}
// In implementing module
// Prefix/Postfix operator test for inbuilt (scalar) datatype 'int'
int x=2;
int y=++x; // 'y' and 'x' now both have value '3'
Console.WriteLine(x++); // Displays '3'
Console.WriteLine(++x); // Displays '5'
Console.WriteLine(ReferenceEquals(x,y)); // Displays 'False'
// Prefix/Postfix operator test of class type 'Test'
Test obj=new Test();
obj.x=1;
Console.WriteLine(obj++); // Must have displayed '1', displays the object type (Test.Test)
Console.WriteLine(++obj); // Must have displayed '3', again displays the object type (Test.Test)
Console.WriteLine(obj.x); // Displays '3' (as expected)
Test obj2=++obj; // Must have the value '4' and must NOT be the reference of obj
// Alternative solution to the above statement can be : 'Test obj2=new Test(++obj);' but isn't there a way to create a new value type in C# by the above statement ??!! (In C++, it can be acheived by overloading the '=' operator but C# doesn't allow it)
Console.WriteLine(obj2.x); // Displays '4' (as expected)
Console.WriteLine(ReferenceEquals(obj,obj2)); // Must display 'False' but displays 'True' showing that 'obj2' is the reference of 'obj'
3 ответа
Вы пытаетесь настроить тип, который объявлен как class
вести себя как struct
, Это не имеет никакого смысла для меня. Если вы измените class Test
в struct Test
удалите конструктор без параметров и переопределите .ToString
Метод, все проблемы ушли.
Во-первых, вы создаете новый экземпляр Test каждый раз, когда вы увеличиваете (Post или Pre). Итак, когда вы нажмете эту строку:
Test obj2 = ++obj;
Как будто ты пишешь:
obj = new Test(obj.x + 1);
Test obj2 = obj;
Во-вторых, что касается проблемы печати, просто переопределите ToString:
public override string ToString()
{
return x.ToString();
}
По сути, вы неправильно поняли, как работает эта строка:
Test obj2 = ++obj;
Если вы думаете об использовании вашего оператора в качестве метода, это все равно что сказать:
obj = Test.operator++(obj);
obj2 = obj;
Так что да, вы в конечном итоге obj
а также obj2
будучи той же ссылкой. Результат ++obj
это значение obj
после применения ++
оператор, но это ++
Оператор влияет на значение obj
тоже.
Если вы используете
Test obj2 = obj++;
тогда это эквивалентно:
Test tmp = obj;
obj = Test.operator++(obj);
obj2 = tmp;
В этот момент значение obj2
будет ссылаться на исходный объект, и vlaue obj
будет ссылаться на вновь созданный объект с более высоким x
значение.
Остальная часть вашего вопроса вокруг результата Console.WriteLine
на самом деле, потому что вы не переопределили ToString()
,
Если вы прочитали предоставленную вами ссылку на удаленный ответ, то:
Test obj2 = ++obj;
Переводится на
temp = operator++(obj);
obj = temp;
obj2 = temp;
Это означает, что они имеют одинаковую ссылку.