DEV Community

Isaac Ayodeji Ikusika
Isaac Ayodeji Ikusika

Posted on

User-defined Conversions: Conversion between Custom Types

Have you ever got this compile time error error CS0029: Cannot implicitly convert type 'string' to 'int'? This happens when you want to pass a string value into an int variable.

var count = 1;
count = "20"; //you get the error
Enter fullscreen mode Exit fullscreen mode

Because C# is statically typed, it will not allow it, hence, the error.

JavaScript is dynamically typed at compile time, so it allows conversion of any type to another:

var count = 1
count = "20" // no error
Enter fullscreen mode Exit fullscreen mode

Another instance where you get the error in C#:

long count = 100;
int myIntCount = count;
Enter fullscreen mode Exit fullscreen mode

We can only solve this problem by converting from one type to another.

Let's talk about the main kinds of type conversion we have in C# dotnet.

  • Implicit conversion: This is straightforward. No exception throw, no data lost. The conversion always succeeds. Example of this is when you are converting a small numerical type to a larger one:
int count = 30;
long numberOfCount = count;
Enter fullscreen mode Exit fullscreen mode
  • Explicit conversion: This is required when information might be lost in the conversion or when the conversion does not just succeed. Here, we use cast expression. An example is converting a larger numerical type to a small one:
long count = 30;
int numberOfCount = (int)count;
Enter fullscreen mode Exit fullscreen mode
  • User-defined conversion: This is our main topic. It is performed by writing a custom method that does the conversion implicitly or explicitly. It is done to convert a custom type to another primitive or custom type. There are some rules to follow to get your conversion working.
    • the conversion methods must be public and static
    • use implicit and explicit keywords to define the kind of conversion you are implementing. As explained above, implicit conversions do not throw exception or data loss unlike explicit conversions.
    • The type (or class) where you have the conversion method must be either a source type or a target type of that conversion. This means if you are converting from type A to type B, the conversion can be defined in either of the two types. For conversion from a custom to primitive type, the conversion is defined in the custom type.

Let's look at an example.


public class Person
{
    private readonly int age;

    public Person(int age)
    {
     //we added a constructor so we could initialise this type with a value 
//and then add a check and throw an exception. 
//It is not compulsory you do this.
     if (age < 16)
         throw new ArgumentException("You are too young for this conversion.");
     this.age = age;
   }

    public static implicit operator int(Person person) => person.age;
    public static explicit operator Person(int age) => new Person(age);

    public override string ToString() => $"I am {age} years old";
}

Enter fullscreen mode Exit fullscreen mode

In the code above, we have a Person type that we want to convert to an integer and back.

Because age field in Person is an integer and can be easily converted to int without throwing an exception, we use an implicit conversion, hence,
public static implicit operator int(Person person) => person.age;

This is not true for a conversion of int to Person because it naturally cannot occur implicitly and it could throw an exception if the age is less than 16. So, we do an explicit conversion:

public static explicit operator Person(int age) => new Person(age);

Now let's test our conversion:


var person = new Person(17);

int number = person; //converting Person type to integer
Console.WriteLine(number);  // output: 17

Person anotherPerson = (Person)number; //converting integer type to Person
Console.WriteLine(anotherPerson);  // output: 17

Enter fullscreen mode Exit fullscreen mode

That was conversion of a custom type to primitive type and back.

Now let's look at conversion of a custom type to another.

Let's add another type:


public class Employee
{
    public string Name { get; set; }
    public int Age { get; set; }

    public static explicit operator Person(Employee employee) => new Person(employee.Age); //conversion of Employee to Person

}

Enter fullscreen mode Exit fullscreen mode

There is nothing particularly different from what we explained before in this code. We are converting from Employee to Person, so we have a conversion method that does that, using the explicit keyword because of an exception that could happen.

Please note that we can have this method on the Person class.

Testing this, we have:


var employee = new Employee {
    Age = 23,
    Name = "John"
};

Person myEmployeePerson = (Person)employee;
Console.WriteLine(myEmployeePerson.ToString()); //output: I am 23 years old

Enter fullscreen mode Exit fullscreen mode

What I enjoy about C# is its extensibility. You should make use of this every chance you get. Type conversion is one of them and it will help you write cleaner code.
You can read more about this on Microsoft docs.

Latest comments (0)