Conversion Operators

Conversion operators facilitate the implicit or explicit casting of user-defined types to built-in types or even other user-defined types. Developers implement a conversion operator so the compiler will know how to convert a user-defined type to another type. Like mathematical and logical operators, the primary reason for implementing conversion operators is convenience. It is never required. You could as easily expose ToType methods, such as ToInt, ToFloat, or ToDecimal. You are already familiar with ToString, which converts from any type to a string.

An implicit cast is available where truncation will not result (a safe cast), whereas explicit casting is required when truncation might occur. For primitive types, a safe cast is available when there is no potential loss of precision or accuracy. When there is potential loss of precision or accuracy, an explicit cast is required. For example, an int can be implicitly assigned to a long. A long value is eight bytes and an int value is four bytes. Therefore, no precision is lost. This makes the cast from int to long safe. The int value will be promoted to a long value. The promotion occurs silently—no warning or notice is given. The reverse, where a long is assigned to an int, requires an explicit cast. Why? There is a loss of precision. Implicit and explicit casting is shown in the following code:

int a = 5;
long b = 10;
b = a;        // implicit cast
a = (int) b;  // explicit cast

C# does not support conversion constructors. A conversion constructor is a one-argument constructor used to create an instance of a type from a different type. Conversion constructors are supported in C++ but not in C#. Conversion constructors were convenient—too convenient, in fact. Conversion constructors sometimes were called transparently when a compiler error for mismatched types was probably more appropriate.

Overload the cast behavior selectively with conversion operator methods. Here is the signature of a conversion operator:

public static implicit operator returntype(type obj)

public static explicit operator returntype(type obj)

The conversion operator syntax has many similarities with overloading mathematical and relational operators. Conversion operators must be public and static. Other modifiers, such as virtual and sealed, are not allowed. Conversion operators that are implicit do not require casting, whereas explicit conversion operators require casting for invocation. I recommend explicit casting in all circumstances. Implicit casting allows the conversion function to be called transparently and sometimes inadvertently, which might have unintended side effects. With explicit casting, developers affirmatively state their intentions through casting. That should be required. The sole parameter is an object of the type from which you are converting. Either the return type or the parameter type should be of the same type as the containing class. If the return type is the containing class, you are describing a conversion to that type. If the parameter is the containing class, the function describes a conversion from the containing type to another type.

Here is sample code of implicit and explicit conversion methods. The ZClass has two conversion operators. The first conversion operator converts ZClass to an int. The second conversion operator converts a YClass to a ZClass:

using System;

namespace Donis.CSharpBook {
    public class Starter {
        public static void Main() {
            ZClass obj1 = new ZClass(5,10);
            int ival = obj1;
            YClass obj2 = new YClass(5);
            ZClass obj3 = obj2;          // error
            ZClass obj3 = (ZClass) obj2;
        }
    }

    public class ZClass {

        public ZClass(int _fielda, int _fieldb) {
            fielda = _fielda;
            fieldb = _fieldb;
        }

        public static implicit operator int(ZClass curr) {
            return curr.fielda + curr.fieldb;
        }

        public static explicit operator ZClass(YClass curr) {
            return new ZClass(curr.field / 2, curr.field / 2);
        }

        public int fielda, fieldb;
    }

    public class YClass {

        public YClass(int _field) {
            propField = _field;
        }

        private int propField;
        public int field {
            get {
                return propField;
            }
            set {
                propField = value;
            }
        }
    }
}

Conversion operators often are overloaded to provide the level of flexibility and functionality available with a primitive type, which can support a variety of casts. In the following code, the conversion operator is overloaded several times to support the conversion of ZClass instances to a variety of types:

using System;

namespace Donis.CSharpBook {

    public class ZClass {

        public ZClass(int _fielda, int _fieldb) {
            fielda = _fielda;
            fieldb = _fieldb;
        }

        public static explicit operator int(ZClass curr) {
            return curr.fielda + curr.fieldb;
        }

        public static explicit operator float(ZClass curr) {
            return (float) (curr.fielda + curr.fieldb);
        }

        public static explicit operator short(ZClass curr) {
            return (short) (curr.fielda + curr.fieldb);
        }

        // and so on

        public int fielda, fieldb;
    }
}

The Operator String Operator

The operator string operator is a special conversion operator that converts a user-defined type to a string. This appears to overlap with the ToString method, which is inherited from System.Object. Actually, every type is also provided an operator string method automatically, which simply calls the polymorphic ToString method. Look at the following code. If a class overrides both the ToString and operator string methods, which method is called by Console.WriteLine?

using System;

namespace Donis.CSharpBook {
    public class Starter {
        public static void Main() {
            ZClass obj = new ZClass();
            Console.WriteLine(obj);
        }
    }

    public class ZClass {

        public static implicit operator string(ZClass curr) {
            return "ZClass.operator string";
        }

        public override string ToString() {
            return "ZClass.ToString";
        }
    }
}

The preceding program displays ZClass.operator string. The operator string method is called to convert the Console.WriteLine operand. Unlike the default operator string method, the custom operator string method in this code does not call ToString. In most circumstances, calling ToString in the operator string method is the best practice eliminating the need to implement a separate operator string method. However, the default operator string method already implements this behavior. You simply override the ToString method with the proper string representation of the type. Inconsistencies and confusion can occur when the operator string method and ToString have separate and unrelated implementations.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.188.131.255