a DotNetStyling - .Net World by Armen Ayvazyan : Custom Type Conversion
Welcome to DotNetStyling Sign in | Join | Help
Add to Technorati Favorites Add to Google Reader or Homepage Add to My AOL Subscribe in FeedLounge Subscribe in Bloglines Add to Excite MIX Add to flurry Add to Pageflakes Subscribe in NewsGator Online


Custom Type Conversion

Conversion in .Net

As we know there are two types of conversion exist in .Net: Explicit and Implicit

The difference allows programmer to use conversion technic in a different way regarding context it used in.

int b = 3;
//explicit conversion of int to short
short a = (short)b;

short c = 13;
//implicit conversion of short to int
int k = c;

 

Explicit conversion force programmer to use conversion signature. Usually explicit conversion uses between types where one type can loose its actual value after conversion and  you have to show explicitly to CLR that you are ready to do this. For instance by converting short to bit the value will be truncated in case if  original value is more than converted type can carry of (after converting value 1000 of short type to bit the converted type will contain value 255).

Implicit conversion does not oblige to use conversion signature which means that you are taking responsibility and know what you are doing. Implicit conversion assumes that both types should be logically similar. It also assumes that by using Implicit conversion there should be not lost of value. For example short can be converted to int without loosing its value (after converting value 8000 of short to int the converted type will contain the same value 8000 as size of int type is much bigger then short.

 

Casting vs. Conversion 

Let's make it clear, conversion is not a casting. Casting is operation between objects which have parent/child relationship.

public class ClassA
{
...
}

 

public class ClassB : ClassA

{ 
...

}

 

ClassB classB = new ClassB();
 

ClassA classA = (ClassA)classB;

or

ClassA classA = classB;

Casting is based on one of OOP fundamentals - Inheritance. By casting classA to classB or vise versa we just able to see the members of casted type.

Converting allows to make custom conversion between the types which event do not have parent/child relationship and it is possible to control the values of properties of converted class.

 

Converting in practice  

For illustration let's assume we have a scenario where two classes represent two containers for wine bottles: MetalContainer  and PlasticBox containers. Let's make them derived from IContainer interface. Basically it is not necessarily to have an interface but it helps to see the logic why classes can be convertible.

There are two properties which should be implemented by each of concrete containers:

  • MaxCapacity - shows number of maximum allowed wine bottles inside of container.
  • Bottles - number of wine bottles currently available in the container.

 

/// <summary>
/// Interface represents container for wine bottles.
/// </summary>

interface IContainer

{

      /// <summary>

      /// Maximum number of bottles can be handled by container.

      /// </summary>

      int MaxCapacity { get;}

 

      /// <summary>

      /// Quantity of available wine bottles inside of the container.

      /// </summary>

      int Bottles { get; set; }

}

 

As you can see, PlasticBox can handle up to 10 wine bottles and in case if somebody will add more than maximum allowed the exception will be thrown.

 

/// <summary>

/// Class represents plastic box container to handle up to 10 wine bottles

/// </summary>

public class PlasticBox : IContainer

{

      /// <summary>

      /// Maximum number of bottles can be handled by box.

      /// </summary>

      public int MaxCapacity

      {

            get { return 10; }

      }

 

      private int _bottles;

      /// <summary>

      /// Current quantity of bottles inside of the box.

      /// </summary>

      public int Bottles

      {

            get { return _bottles; }

            set

            {

                  if (value > MaxCapacity)

                        new Exception("You cannot add bottles more than container able to handle.");

 

                  _bottles = value;

            }

      }

 

}


 The same with the MetalContainer but with one difference that this container is much bigger and can contain up to 100 pieces of wine bottles.

/// <summary>

/// Custom container which can handle up to 100 wine bottles.

/// </summary>

public class MetalContainer : IContainer

{

      /// <summary>

      /// Maximum number of bottles which can be handled by container.

      /// </summary>

      public int MaxCapacity

      {

            get { return 100; }

      }

 

      private int _bottles;

      /// <summary>

      /// Current quantity of bottles insinde of the container.

      /// </summary>

      public int Bottles

      {

            get { return _bottles; }

            set

            {

                  if (value > MaxCapacity)

                        new Exception("You cannot add bottles more than container able to handle.");

 

                  _bottles = value;

            }

      }

}

 

Well, basically what we are going to achieve it is to have ability to convert one type of container to another with handling of Bottles property as containers have different capacity.

 

Explicit Conversion. 

If we will try to convert object with type MetalContainer to PlasticBox without any additional implementation we will get compilation error:

MetalContainer RedContainer = new MetalContainer();

RedContainer.Bottles = 53;

 

//Error during compilation "Cannot cast expression MetalContainer to PlasticBox"

PlasticBox RedBox = (PlasticBox)RedContainer;

 

To accomplish conversion between types .Net gives us ability to implement conversion operator.

public static explicit operator PlasticBox(MetalContainer bmc)

{

      PlasticBox pb = new PlasticBox();

      pb.Bottles = (bmc.Bottles<=pb.MaxCapacity)? bmc.Bottles : pb.MaxCapacity;

 

      return pb;

}

As you can see the actual implementation is really simple, we are creating the instance of converted type, filling the appropriate values and returning the result. Let's look at the method declaration:

  • Implemented method of course should be visible for outside usage, so it should be public or at least internal
  • method should be static as (PlasticBox)RedContainer conversion should work without creating instance of MetalContainer object first.
  • explicit operator keywords show that convertor has to be explicit.
  • name of the method is actually a name of type which instance you achieve to get after conversion.
  • input parameter is an original instance which should be converted. It is obvious that instance type should be the same as the type of  class where method located.

Let's run one more time the same code with explicit conversion but with added console outputs just to see the result on the screen:

 

 

MetalContainer RedContainer = new MetalContainer();

RedContainer.Bottles = 53;

Console.WriteLine("Bottles inside of Red Metal Container: {0}", RedContainer.Bottles);

 

PlasticBox RedBox = (PlasticBox)RedContainer;

Console.WriteLine("Bottles inside of Red Plastic Box: {0}", RedBox.Bottles);

 

RedBoxOutput

As you can see RedBox (PlasticBox) is actually is a result of converting RedContainer (MetalContainer) to PlasticBox type's shape.

 

 

Implicit Conversion. 

This is actually ability of converting without specific signature, but just setting one object to another. This actually means that you can do something like this :

PlasticBox YellowBox = new PlasticBox();

YellowBox.Bottles = 9;

//Without implementation of implicit conversion logic, compiler will raise an error

//"Cannot convert source type PlasticBox to target type MetalContainer"

MetalContainer YellowContainer = YellowBox;

 

Let's now implement implicit conversion logic between two types PlasticBox and MetalContainer. Actually we will implement implicit conversion of PlasticBox to MetalContainer. Inside of PlasticBox class let's create implicit operation:

 

public static implicit operator MetalContainer(PlasticBox pb)

{

      MetalContainer bmc = new MetalContainer();

      bmc.Bottles = pb.Bottles;

      return bmc;

}

As you can see method looks pretty the same like implemented explicit convertor for MetalContainer just with difference that here it used "implicit" keyword instead of "explicit"

 

Let's now to run code with implicit conversion:

 

PlasticBox YellowBox = new PlasticBox();

 

YellowBox.Bottles = 9;

Console.WriteLine("Bottles inside of Yellow Plastic Box: {0}", YellowBox.Bottles);

 

//No error message anymore, PlasticBox will be implicitly converted to MetalContainer

MetalContainer YellowContainer = YellowBox;

Console.WriteLine("Bottles inside of Yellow Metal Container: {0}", YellowContainer.Bottles);

YellowBoxOutput

 

By assigning YellowBox to YellowContainer, YellowBox is not actually became a MetalContainer but instance of MetalContainer has been returned to the YellowContainer. 

This is good but what about value type objects. Is it possible to involve value type objects to the conversion process. 

 

//Compiler error "Cannot convert source type 'int' to target type 'MetalContainer'

MetalContainer BlueContainer = 3;

 

Let's add implicit conversion logic inside of MetalContainer class with involving 'int' value type in the game.

 

public static implicit operator MetalContainer(int bottles)

{

      MetalContainer bmc = new MetalContainer();

      bmc.Bottles = (bottles <= bmc.MaxCapacity) ? bottles : bmc.MaxCapacity;

 

      return bmc;

}

 

As you can see implementation is similar to the PlasticBox implicit convertor but input parameter of method is not reference type but 'int' value. The point of this implementation is that to create an instance of MetalContainer it is enough to set a number of wine bottles and the instance of MetalContainer will be created with already filled "Bottles" property.

 

//MetalContainer instance will be returned by filed Bottles property value to 3

MetalContainer BlueContainer = 3;

Console.WriteLine("Bottles inside of Blue Metal Container: {0}", BlueContainer.Bottles);

 

BlueBoxOutput

 

Basally that's it. I am not sure if conversion between different reference types is a common feature but anyhow you can easily implement one of Explicit or Implicit conversion if it will be necessarily.

Technorati tags: , , , ,
kick it on DotNetKicks.com
Posted: 14. září 2007 11:22 by admin
Filed under: ,

Comments

New Comments to this post are disabled