Matthew Layton
Matthew Layton

Reputation: 42390

Ambiguous implicit user defined conversions in .NET

I recently wrote a couple of structs in .NET, to which I then added implicit conversion operators

Example:

public struct Alpha
{
    internal string value;

    public static implicit operator Alpha(Beta b)
    {
        return new Alpha() { value = b.value };
    }

    public static implicit operator Beta(Alpha a)
    {
        return new Beta() { value = a.value };
    }
}

public struct Beta
{
    internal string value;

    public static implicit operator Alpha(Beta b)
    {
        return new Alpha() { value = b.value };
    }

    public static implicit operator Beta(Alpha a)
    {
        return new Beta() { value = a.value };
    }
}

Test:

Alpha a = default(Alpha);
Beta b = a;
// Ambiguous user defined conversions 'Alpha.implicit operator Beta(Alpha)' and 'Beta.implicit operator Beta(Alpha)' when converting from 'Alpha' to 'Beta'

I would like to know what the rules / best practices are surrounding implicit conversion in C#?

Note to self: My gut feeling is that types should not return objects of another type through implicit conversion? i.e. Beta should not return Alpha via implicit conversion, and vice-versa, however, Beta should return Beta, and Alpha should return Alpha

Example (fixed):

public struct Alpha
{
    internal string value;

    public static implicit operator Alpha(Beta b)
    {
        return new Alpha() { value = b.value };
    }
}

public struct Beta
{
    internal string value;

    public static implicit operator Beta(Alpha a)
    {
        return new Beta() { value = a.value };
    }
}

Is my assumption correct?

Upvotes: 1

Views: 1519

Answers (2)

AaronLS
AaronLS

Reputation: 38392

You have a Alpha(Beta x) defined in both classes, thus it is ambiguous which one should be used. Allow each class to handle only the conversion to itself. In other words, struct Alpha implements Alpha(Beta b) because it best knows how to create an instance of itself. Also, I would consider implementing explicit conversions instead of implicit. It can sometimes cause bugs or unexpected conversions accidentally, and when dealing with complex classes are often "lossy" conversions.

public struct Alpha
{
    internal string value;

    public static implicit operator Alpha(Beta b)
    {
        return new Alpha() { value = b.value };
    }
}

public struct Beta
{
    internal string value;

    public static implicit operator Beta(Alpha a)
    {
        return new Beta() { value = a.value };
    }
}

The only time you'd likely implement "both ways" in a single class, is if the other class has no knowledge of your new class. This is the more common scenario when you want to support conversion to-from a pre-existing class/struct such as supporting conversion to-from a framework type:

public struct Alpha
{
    internal string value;

    public static implicit operator Alpha(string b)
    {
        return new Alpha() { value = b };
    }

    public static implicit operator string(Alpha a)
    {
        return  a.value;
    }
}

Upvotes: 5

BlackBear
BlackBear

Reputation: 22989

No, your assumpion is not correct (even though you wrote working code thanks to it). The problem in your code is that you have defined the same conversion operators in both classes, this is why they are ambiguous; the compiler cannot decide which one to use.

You can read more in section 6.4.3 (Evaluation of user-defined conversions) of the C# 4.0 Language Specification.

Upvotes: 0

Related Questions