Предефиниране на оператори в C#
Въведение
Операторите служат за групиране на различни операнди в изрази. Различните оператори имат различна семантика, в зависимост от типа, с който работят. Например операторът +, ако се използва с числа, означава "събиране", а ако се използва с низове - "конкатенация".
Всеки оператор има определена асоциативност, която определя в каква посока ще се извършат изчисленията. Например, операторът + е с лява асоциативост. Това означава, че операцията a+b е еквивалентна на към a прибавяме b. Операторът = е с дясна асоциативност. За това операцията a=b=5 е еквивалентна на b=5, след което a=b.
Всеки оператор си има и собствен приоритет. Например изразът a-b*c е еквивалентен на a-(b*c).
Някои ограничения
Въпреки възможността, която ни предоставя езикът C# да предефинираме оператори, има някои съвсем смислени ограничения в тази насока:
- НЕ можете да променяте асоциативността на операторите
- НЕ можете да създавате нови оператори
- НЕ можете да променяте значението на операторите (например: 1+1=2 и това не можете да го промените)
- НЕ можете да предефинирате някои оператори (като точката, която служи за достъп до член на обекта)
Самото предефиниране
Малко "суха" материа
Предефинирането на оператори изглежда така:
- public static [Class] operator[Operator] ([param1 [, param2]])
- операторът е публичен
- операторът е статичен
- бинарните оператори (пр. +) притежават два аргумента, а унарните (пр. ++) - само един
Същността на темата
Нека имаме следния клас.
- class MyClass
- {
- private int myValue;
- public int MyValue
- {
- get { return this.myValue; }
- set { this.myValue = value; }
- }
- public MyClass (int value)
- {
- this.MyValue = value;
- }
- }
Искаме да можем да извършваме операциите събиране, изваждане, умножение и деление с обекти от този тип. За тази цел ще трябва да си предефинираме тези оператори. Ето един пример, който илюстрира как стават нещата на практика.
- public static MyClass operator+ (MyClass lObj, MyClass rObj)
- {
- return new MyClass (lObj.MyValue + rObj.MyValue);
- }
В случая указахме, че когато събираме два обекта от тип MyClass, искаме всъщност да събираме стойностите на техните полета myValue. По аналогичен начин, трябва да предефинираме и операторите за изваждане, умножение и деление.
Много е удобно (и е честа практика), когато предефинираме бинарни оператори, единия аргумент да го кръщаваме lObj (от left - ляв), а другия съответно rObj (от right - десен). Така е по-лесно да знаем с кой от двата обекта работим.
Сега обаче искаме да можем да извършваме действия не само с обекти от нашия тип. Например искаме да можем да събираме обект от нашия тип с цяло число. Ето и решението на този проблем.
- public static MyClass operator+ (MyClass lObj, int rObj)
- {
- return (lObj + new MyClass(rObj));
- }
Забележете, че когато събирам обект от тип MyClass и цяло число, всъщност събираме два обекта от тип MyClass. Това се прави с цел, запазването на главната логика за събирането на обекти от нашия тип. Въпреки, че в случая нашето събиране се свежда до много проста операция, в много други случаи ще се изисква нещо много по-сложно. И тогава ще се забележи предимството на този метод за запазване на главната логика.
Има един "проблем" - както сме предефинирали в момента оператора за събиране, можем да събираме само обекти от тип MyClass с целия числа (или с други обекти от същия тип). Но, ако се опитаме да събереме цяло число с обект от тип MyClass, ще възникне грешка. Разбира се има решение на този проблем. Ето го и него.
- public static MyClass operator+ (int lObj, MyClass rObj)
- {
- return (new MyClass(lObj) + rObj);
- }
Искам да спомена само, че изразът a += b е еквивалентен на a = a + b.
Остана само да покажа, как става предефинирането на унарни оператори (++ / --). Следния пример напълно ще изясни същността на въпроса.
- public static MyClass operator++ (MyClass obj)
- {
- return (obj + new MyClass(1));
- }
Заключение
Мисля, че с написаното до тук, съм ви дал една представа за това, как става предефиниране на оператори в C#. Ако имате неясноти по въпроса, можете да се обърнете към мен.
Коментари
Към тази статия все още няма коментари. Бъдете първи и напишете вашия коментар.

