Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What implicit conversions are supported when using < and > operators?

I have got a struct:

public struct Decibel
{
    public readonly double Value;

    public Decibel (double value)
    {
        Value = value;
    }

    public static implicit operator Decibel (double decibels)
    {
        return new Decibel (decibels);
    }

    public static implicit operator double (Decibel decibels)
    {
        return decibels.Value;
    }
}

And now I can do:

bool x = new Decibel (0) < new Decibel (1);

It seems the compiler is smart enough to convert Decibel to double, and then use the < operator for doubles?

I had different struct named Duration, which was wrapping TimeSpan. It had implicit conversions for TimeSpan to/from Duration, but the < and > operators are not working for it.

Does c# only recognize conversion between primitive types?

like image 870
apocalypse Avatar asked Apr 29 '15 08:04

apocalypse


People also ask

What is the difference between implicit type conversion and?

Implicit conversion is the conversion in which a derived class is converted into a base class like int into a float type. Explicit conversion is the conversion that may cause data loss. Explicit conversion converts the base class into the derived class.

Which conversion can be performed implicitly?

We cannot perform implicit type casting on the data types which are not compatible with each other such as: Converting float to an int will truncate the fraction part hence losing the meaning of the value. Converting double to float will round up the digits.

What is the example of implicit conversion?

Implicit conversions For example, a variable of type long (64-bit integer) can store any value that an int (32-bit integer) can store. In the following example, the compiler implicitly converts the value of num on the right to a type long before assigning it to bigNum .

What two commands will perform implicit conversion?

Answer: Cast and Convert.


1 Answers

Firstly note that C# will allow a maximum of ONE implicit user-defined conversion between types.

So when you compare two instances of Decibel, the compiler sees that it can use a user-defined implicit conversion to convert a Decibel to a double with which to compare.

However when you compare two instances of Duration, the compiler cannot find any single implicit conversion which it can use to allow the comparison. The compiler will not consider any user-defined comparison operators for any of the types to which the type can be implicitly converted. It will only look for built-in comparison operators for any of the types to which the type can be implicitly converted.

Therefore the compiler will not use the implicit conversion to TimeSpan, even though TimeSpan provides a user-defined comparison operator that could theoretically be used.

Also note that even if the TimeSpan class provided an implicit conversion to double, the compiler would still not use it, since it will only consider at most one implicit user-defined conversion in the chain of implicit conversions.

In other words, given these structs:

public struct Number
{
    public readonly double Value;

    public Number(double value)
    {
        Value = value;
    }

    public static implicit operator Number(double duration)
    {
        return new Number(duration);
    }

    public static implicit operator double(Number number)
    {
        return number.Value;
    }
}

public struct NumberWrapper
{
    public readonly Number Value;

    public NumberWrapper(Number value)
    {
        Value = value;
    }

    public static implicit operator NumberWrapper(Number duration)
    {
        return new NumberWrapper(duration);
    }

    public static implicit operator Number(NumberWrapper number)
    {
        return number.Value;
    }
}

This code will compile:

bool x = new Number(1) < new Number(2);

And so of course will this:

Number n1 = new NumberWrapper(1);
Number n2 = new NumberWrapper(2);
bool z = n1 < n2;

But this won't:

bool y = new NumberWrapper(1) < new NumberWrapper(2);

because NumberWrapper doesn't have an implicit conversion to any type that supports < without any further implicit conversions.

Note that all primitive numeric and enumeration types (e.g. char, short, int, long, float, double, decimal, enum) provide built-in comparison operators. All other types can only provide user-defined comparison operators.

User-defined comparison operators look like this:

public static bool operator < (MyType lhs, MyType rhs) ...
like image 151
Matthew Watson Avatar answered Oct 07 '22 00:10

Matthew Watson