2016-08-30 22 views
2

В следующем коде есть проблема с запуском с непредвиденными ссылками, полученными путем назначения инструкции приращения постфикса/префикса, как показано ниже в коде. Также может ли кто-нибудь предложить мне способ лечения объектов как типов значений в C#, как предложено ниже, если они есть?Перегрузка операторов префикса и Postfix в 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' 
+2

Ну да, вы не переопределили 'ToString()'. В этот момент половина ваших возражений уходит. Это действительно поможет, если вы напишете [mcve], демонстрирующий проблему * single *. –

+0

@ user3185569: Я удалил этот бит комментария. Мне кажется, что часть «obj» и «obj2» должна быть в порядке ... Это не помогает в том, что здесь так много проблем. –

+0

На самом деле нет, я вижу, что не так с частью 'Test obj2 = ++ obj'. Будет добавлен ответ для этого. –

ответ

1

Вы пытаетесь настроить тип, который объявлен как class, чтобы вести себя как struct. Для меня это не имеет никакого смысла. Если вы меняете class Test на номер struct Test, удалите конструктор без параметров и переопределите метод .ToString, все проблемы исчезли.

Во-первых, вы создаете новый экземпляр теста каждый раз, когда вы увеличиваете (пост или пре).Так что, когда вы нажмете эту строку:

Test obj2 = ++obj; 

Как будто вы пишете:

obj = new Test(obj.x + 1); 
Test obj2 = obj; 

Во-вторых, и как для выпуска печати, просто переопределить ToString:

public override string ToString() 
{ 
    return x.ToString(); 
} 
+0

Ну, тогда как я могу заставить их не иметь такую ​​же ссылку? Спасибо за ответ. – hecate

+0

@hecate. Тогда нет причин иметь «Тест» как класс, если вы не хотите, чтобы с ним обращались по ссылке. Затем преобразуйте его в «Struct». При этом у вас будет копия по значению семантики, и эта проблема исчезнет. – user3185569

+0

Спасибо. Преобразование класса «Тест» в структуру помогло. Еще раз спасибо :) – hecate

1

Если вы читали link вы предоставили для удаленного ответа, то:

Test obj2 = ++obj; 

переведен на

temp = operator++(obj); 
obj = temp; 
obj2 = temp; 

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

+0

Ну, тогда как я могу заставить их не иметь такую ​​же ссылку? Спасибо за ответ. – hecate

+0

Вы не можете, если хотите просто использовать оператор ++. Для версии 'увеличенного' создается только один экземпляр. – Maarten

4

В принципе, вы поняли, как работает эта линия:

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().

+0

Ну, тогда как я могу заставить их не иметь такую ​​же ссылку? Спасибо за ответ. – hecate

+0

@hecate: Вы не можете. Посмотрите, что означает 'test obj2 = ++ obj;' - последняя часть его - 'obj2 = obj;'. Как бы вы ожидали, что дать разные рекомендации? Обратите внимание, что если 'Test' является неизменным, это не имеет значения. (Как уже упоминалось в другом месте, вы можете сделать 'Test' структурой, но тогда нет ссылок нигде ...) –