I saw some code yesterday which at first glance looked odd. A method was accepting a parameter of a custom type named Money and the calling code was passing in a double value. After a bit of confusion I recalled that the C# language natively supports conversion operators.
If you have a custom type, you have the option to define conversion operators on your type which let you convert from your custom type to a target type and from the target type back to the custom type. Conversion can be implicit or explicit. Implicit conversion means that users of your custom type can convert to the target type without having to perform a type cast operation. Explicit conversion forces a type cast to be performed.
To demonstrate this, we'll use the case I came across. Imagine we have a Money class which is composed of a currency and a value that the money represents. We may initially decide that we want the Money class to be flexible so that users of the class can treat it is a value (a double type in this case). This means that when a double is expected (e.g. as an argument to a method), the user of the class can pass the Money instance which will implicitly be converted to its value form. Moreover, we can also make the conversion from double to Money implicit, meaning that whenever a Money instance is expected, we can pass in a double. Our initial attempt at the Money class implementation would therefore look something like:
Cannot implicitly convert type 'ConversionOperators.Money' to 'double'. An explicit conversion exists (are you missing a cast?)
Cannot implicitly convert type 'double' to 'ConversionOperators.Money'. An explicit conversion exists (are you missing a cast?)
As the errors point out, we now need to explicitly cast between the types - as demonstrated in the code below.
If you have a custom type, you have the option to define conversion operators on your type which let you convert from your custom type to a target type and from the target type back to the custom type. Conversion can be implicit or explicit. Implicit conversion means that users of your custom type can convert to the target type without having to perform a type cast operation. Explicit conversion forces a type cast to be performed.
To demonstrate this, we'll use the case I came across. Imagine we have a Money class which is composed of a currency and a value that the money represents. We may initially decide that we want the Money class to be flexible so that users of the class can treat it is a value (a double type in this case). This means that when a double is expected (e.g. as an argument to a method), the user of the class can pass the Money instance which will implicitly be converted to its value form. Moreover, we can also make the conversion from double to Money implicit, meaning that whenever a Money instance is expected, we can pass in a double. Our initial attempt at the Money class implementation would therefore look something like:
public class Money
{
public string Currency { get; set; }
public double Value { get; set; }
// Implicit conversion from Money to double
public static implicit operator double(Money money)
{
return money.Value;
}
// Implicit conversion from double to Money
public static implicit operator Money(double @double)
{
return new Money { Value = @double };
}
}
With the above class, the following code would therefore compile:
{
public string Currency { get; set; }
public double Value { get; set; }
// Implicit conversion from Money to double
public static implicit operator double(Money money)
{
return money.Value;
}
// Implicit conversion from double to Money
public static implicit operator Money(double @double)
{
return new Money { Value = @double };
}
}
var money = new Money() { Currency = "GBP", Value = 10.5 };
// Implicitly convert Money to a double
double moneyValue = money;
// Convert a double to Money (Money.Currency will be null!)
Money moneyInstance = moneyValue;
Notice that when converting a Money instance to a double, we would lose
information on the Money instance (the currency in this case). Also,
when converting a double to a Money, the currency is never set. It would
therefore make more sense in this scenario to use explicit conversion
operators so that the user is forced to be aware that they could lose
information in the conversion or have a partially initialised Money
instance (it isn't a straight-forward conversion). To define explicit
conversion on the Money class, the only change required would be to
replace the "implicit" keyword with the "explicit" keyword on the two
conversion methods. The Money class would now look like:
// Implicitly convert Money to a double
double moneyValue = money;
// Convert a double to Money (Money.Currency will be null!)
Money moneyInstance = moneyValue;
public class Money
{
public string Currency { get; set; }
public double Value { get; set; }
// Explicit conversion from Money to double
public static explicit operator double(Money money)
{
return money.Value;
}
// Explicit conversion from double to Money
public static explicit operator Money(double @double)
{
return new Money { Value = @double };
}
}
After making this change, the example calling code above would fail to
compile with the following two compile-time error messages:
{
public string Currency { get; set; }
public double Value { get; set; }
// Explicit conversion from Money to double
public static explicit operator double(Money money)
{
return money.Value;
}
// Explicit conversion from double to Money
public static explicit operator Money(double @double)
{
return new Money { Value = @double };
}
}
Cannot implicitly convert type 'ConversionOperators.Money' to 'double'. An explicit conversion exists (are you missing a cast?)
Cannot implicitly convert type 'double' to 'ConversionOperators.Money'. An explicit conversion exists (are you missing a cast?)
As the errors point out, we now need to explicitly cast between the types - as demonstrated in the code below.
var money = new Money() { Currency = "GBP", Value = 10.5 };
double moneyValue = (double) money;
Money moneyInstance = (Money) moneyValue;
double moneyValue = (double) money;
Money moneyInstance = (Money) moneyValue;
Sign up here with your email
ConversionConversion EmoticonEmoticon