Example
In order to illustrate the implicit conversion feature we're going to use the following classes:
namespace Langexplr.Experiments
{
public class Complex
{
public double Real { get; set; }
public double Img { get; set; }
public static implicit operator Complex(double real)
{
return new Complex() { Real = real };
}
public static implicit operator Polar(Complex complex)
{
return new Polar() { Angle = Math.Atan(complex.Img/complex.Real),
Length = Math.Sqrt(complex.Real*complex.Real +
complex.Img*complex.Img) };
}
public static implicit operator double(Complex complex)
{
return Math.Sqrt(complex.Real*complex.Real +
complex.Img*complex.Img);
}
}
public class Polar
{
public double Angle { get; set; }
public double Length { get; set; }
}
}
The
Complex
class is a simple definition of a complex number. The Polar
class is defined(conveniently) to represent a complex number in polar form. The Complex
class defines three implicit conversions:- From
double
to a complex number - From
Complex
toPolar
- From
Complex
todouble
The following C# code shows a use of this feature:
using Langexplr.Experiments;
using System;
class main
{
public static void Main(string[] args)
{
Complex c = 10.3;
Polar p = new Complex() {Real = 12.3, Img = 5.2};
double abs = c;
Console.WriteLine("abs:{0} Polar: {1},{2}", abs ,p.Angle ,p.Length);
}
}
By looking at the definitions generated by the compiler for the
Complex
class, we can see several definitions for the op_Implicit
method with different parameters and return types....
.method public hidebysig specialname static
class Langexplr.Experiments.Complex
op_Implicit(float64 real) cil managed
...
.method public hidebysig specialname static
class Langexplr.Experiments.Polar
op_Implicit(class Langexplr.Experiments.Complex complex) cil managed
...
.method public hidebysig specialname static
float64 op_Implicit(class Langexplr.Experiments.Complex complex) cil managed
...
Now these uses of the
Complex
class will be presented on different .NET languages.IronPython
As described in "Dark Corners of IronPython" by Michael Foord the
clr.Convert
function can be used to convert between types using the op_Implicit
if necessary.For example:
import clr
clr.AddReference("ImplicitTest")
from Langexplr.Experiments import *
from System import Double
c = clr.Convert(10.3, Complex)
nC = Complex()
nC.Real = 12.3
nC.Img = 5.2
p = clr.Convert(nC, Polar)
abs = clr.Convert(c, Double)
print 'abs: %(0)f Polar: %(1)f,%(2)f\n' % \
{ '0': abs, '1' : p.Angle, '2' : p.Length }
IronRuby
IronRuby will use the
op_Implicit
definition if a conversion required at a particular call. I couldn't find a nice way to do this directly as with IronPython's clr.Convert
. However the following function definition seems to do the trick:
def dotnet_convert(value,type)
f = System::Func[type,type].new {|x| x}
f.invoke(value)
end
This conversion function works since IronRuby tries to convert the value to the expected .NET type in the call to 'invoke' .
Using this definition we can write:
require 'ImplicitTest.dll'
c = dotnet_convert(10.3,Langexplr::Experiments::Complex)
nC = Langexplr::Experiments::Complex.new
nC.Real = 12.3
nC.Img = 5.2
p = dotnet_convert(nC,Langexplr::Experiments::Polar)
abs = dotnet_convert(c,System::Double)
print "abs: #{abs} Polar: #{p.Angle},#{p.Length} \n"
F#
In F# we can call the
op_Implicit
method directly and F# will use type inference to determine the correct overload to use.For example:
open Langexplr.Experiments
let c : Complex = Complex.op_Implicit 10.3
let p : Polar = Complex.op_Implicit (new Complex(Real=12.3, Img=5.2))
let abs : double = Complex.op_Implicit c
System.Console.WriteLine("1. {0} Polar: {1},{2} ", abs, p.Angle, p.Length )
There's a nice post called "F# – Duck Typing and Structural Typing" by Matthew Podwysocki, which describes a nice way to define a generic function to use the op_Implicit operator.
let inline convert (x:^a) : ^b = ((^a or ^b) : (static member op_Implicit : ^a -> ^b) x )
This function can be used as follows:
let c2:Complex = convert 10.3
let p2:Polar = convert (new Complex(Real=12.3, Img=5.2))
let abs2:float = convert c
System.Console.WriteLine("2. {0} Polar: {1},{2} ",abs2,p2.Angle,p2.Length)
VB.NET
Finally in Visual Basic .NET the implicit conversion is used automatically as in C#. For example:
Imports System
Imports Langexplr.Experiments
Module Test
Sub Main
Dim c As Complex = 10.3
Dim p As Polar = new Complex() With { _
.Real = 12.3, _
.Img = 5.2 _
}
Dim abs As Double = c
Console.WriteLine("abs:{0} Polar: {1},{2}",abs,p.Angle,p.Length)
End Sub
End Module