Pages

Thursday, February 6, 2014

Create implicit and explicit user-defined type converions in C#

I bet you had to write tons of static methods to convert between a user-defined type to another type, and that it always made your code very ugly and verbose, also creating lots of "helpers".

Well, C# has a nifty way to facilitate that for us.

Apart from using the keyword operator to overload default arithmetic operations, we can use it in conjunction with the implicit and explicit keywords to create new user-defined type conversions. One should already know the difference between explicit and implicit conversions.


Implying it


By defining a new operator using the implicit keyword, you can easily hide all of those static method calls, and write simple code, such as this:

var foo = new Foo
{
    Size = 10,
    Name = "Foo"
};

Bar bar = foo;

// Notice that we're not talking about polymorphism, 
// as there's no inheritance between the classes:
class Bar
{
    public string BarInfo { get; set; }
}

class Foo
{
    public int Size { get; set; }
    public string Name { get; set; }       
}

To do that, we simply defined a new implicit operator between the two types, such as:

public static implicit operator Bar(Foo foo)
{
    var bar = new Bar { BarInfo = string.Concat(foo.Size, " - ", foo.Name) };

    return bar;
}

The above code simply concatenates both properties of our Foo object and sets Bar's BarInfo property with the result.

MSDN says that the operator should be defined on the source type, although it works well if you define it on the target type. Also, it states that you should only use implicit conversions for user-defined types like this if you're absolutely sure that no exceptions may be thrown. If there's too much data transformation, and you may eventually get an exception, then it advises you to use explicit conversions instead.


Expliciting it

Let's say we have a Foo type, which already has an implicit conversion to a Bar type. But now there's this new BigFoo type for which we want to convert our Foo. A Foo needs to have a size of at least 10 to be considered a BigFoo. So what we want to do is:

var foo = new Foo
{
    Size = 10,
    Name = "Foo"
};

BigFoo bigFoo = (BigFoo)foo;

And to enable such code, we define an explicit operator between the two types on the Foo class:

class Foo
{
    public int Size { get; set; }
    public string Name { get; set; }       
        
    public static explicit operator BigFoo(Foo foo)
    {
        if (foo.Size < 10)
        {
            throw new InvalidCastException("Foo is not big enough to be a BigFoo!");
        }

        var bigFoo = new BigFoo { Name = foo.Name };

        return bigFoo;
    }
}
I'd rather read the above conversion code examples as they are then reading code that looks like this:
var foo = new Foo
{
    Size = 10,
    Name = "Foo"
};

var bigFoo = Foo.TryConvertToBigFoo(foo);
var bar = Foo.ConvertToBar(bar);

No comments:

Post a Comment