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
Whilst you can't do this directly, there are some short cuts you can use to enable code-reuse.
public class Base
{
protected int m_value;
...
// From int
public static implicit operator Base(int Value)
{
Base newObject = new Base();
newObject.FromInt(Value);
return newObject;
}
...
// To string
public static explicit operator string(Base Value)
{
return String.Format("${0:X6}", (int)Value);
}
//Instance FromInt()
protected void FromInt(int value)
{
m_value = value;
}
}
public class Derived : Base
{
// To string, re-use Base-ToString
public static explicit operator string(Derived Value)
{
// Cast (Derived)Value to (Base)Value and use implemented (Base)toString
return (string)(Base)Value;
}
// Use FromInt, which has access to instance variables
public static implicit operator Base(int Value)
{
// We can't use (Base)obj = Value because it will create
// a "new Base()" not a "new Derived()"
Derived newObject = new Derived();
newObject.FromInt(Value);
return newObject;
}
}
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.
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
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.
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.
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).