Перегрузка префиксного и постфиксного операторов в 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;

Это означает, что они имеют одинаковую ссылку.

Другие вопросы по тегам