views:

645

answers:

5

Hello all, I'm not sure what I'm doing wrong here. I have a generic class, which is basically a glorified integer, with a few methods for certain string formatting, as well as into/from string and int conversions:

public class Base
{
    protected int m_value;
    ...
    // From int
    public static implicit operator Base(int Value)
    {
        return new Base(Value);
    }
    ...
    // To string
    public static explicit operator string(Base Value)
    {
        return String.Format("${0:X6}", (int)Value);
    }
}

And it functions fine. I can successfully use implicit and explicit conversions:

Base b = 1;
Console.WriteLine((string)b);  // Outputs "$000001", as expected.

Then I derive from this class, different child classes, which turn on/off different named bits in m_value. For example:

public class Derived : Base
{

}

And then I cannot use my implicit to/from int conversions:

Derived d = 3;
// Cannot implicitly convert type 'int' to 'Derived'. An explicit conversion exists (are you missing a cast?)

Even this gives the same error:

Derived d = (int)3;

Are the implicit/explicit conversions not inherited in the derived class? This will require a lot of code copying if not.

Thanks, Jonathon

RESPONSE Thank you so much for the quick responses! You all deserve the 'answer' checkmark, they're all very good answers. The key is to think about the types on both sides of the equal sign. Now that I think about it like that, it makes perfect sense.

I obviously only have to re-write my "to Derived" conversions. The "to Int32, String, etc" conversions still apply.

This was my first question on stackoverflow, but I promise I'll be back soon, hopefully contributing on both ends of this question/answering!

Thanks again, Jonathon

+3  A: 

No, it will not work that way. The compiler will not implicitly downcast from a base to a derived for you. Basically, you can't do ...

D d = new B();

You will get your base class implmentations from your string cast, because it will do the implicit upcasting for you.

You could do a work around if you didn't want to copy your methods to your derived class with an extension function on integers, like (assuming your derived class is called D) ...

public static class Ext
{
    public static D IntAsD(this int val)
    {
        return new D(val);
    }
}

Then, you could do what you want with ...

D d1 = 5.IntAsD();

Granted, it's not perfect, but it might fit your needs.

JP Alioto
+3  A: 

The reason

Derived d = (int)3;

does not work is because the type Derived does not exactly match the return value of the operator Base as is required to invoke this operator. Notice that you haven't provided any conversion operators that contain the code new Derived(...), so it is not surprising that you can't make new Derived instances this way.

Note, however, that the opposite conversion

Derived v = ...;
string s = (string)v;

will work fine (as if it were "inherited", although this is not really inheritance due to the static keyword).

binarycoder
+2  A: 

Overloaded operators (including conversions) are inherited, but not in a way you seemingly expect them to. In particular, they aren't magically extended to operate on derived types. Let's look at your code again:

Derived d = 3;

At this point the compiler has two classes to work with, System.Int32, and Derived. So it looks for conversion operators in those classes. It will consider those inherited by Derived from Base, namely:

public static implicit operator Base(int Value);
public static explicit operator string(Base Value);

The second one doesn't match because the argument should be an Int32. The first one does match the argument, but then it's return type is Base, and that one doesn't match. On the other hand, you can write this:

string s = (string) new Derived();

And it will work, because the explicit operator in Base exists and is applicable (argument is expected to be Base, Derived inherits from Base and therefore matches the argument type).

The reason why the compiler won't automagically redefine conversion operators in derived types "properly" is because there's no generic way to do so.

Pavel Minaev
A: 

No they're not. Here's the clue:

public **static** implicit operator Base(int Value)

static methods in C# are just global functions with access to private class members. They're never inherited

Orion Edwards
Though it is correct that static methods are not inherited, that's completely irrelevant to this question. The relevant section of the C# 3.0 spec is section 6.4.3, where we describe which types are searched for static operators: "This set consists of the source type and its base classes and the target type and its base classes".
Eric Lippert
oops. I'd delete the incorrect answer but your comment is well worth keeping, so it'll have to stay there to make me look bad :-)
Orion Edwards
+1  A: 

The conversion/operator methods are a convenience but as others have noted, they're not always going to do what you want. Particularly, if the compiler doesn't see the right types on both sides of the = sign, it won't even consider your conversion/operator. This is why if you do the following you get a compiler warning:

object str = "hello";
if ( str == "hello" ) {
}

Furthermore, custom conversions are not considered when using the as/is keywords.

When thinking about implementing an explicit/implicit conversion, you should also consider implementing IConvertible and/or implementing a TypeConverter. This gives you a lot more flexibility when having a base class handle type conversions.

Josh Einstein