locked
Error CS0554. user defined conversion to/from derived class RRS feed

  • Question

  • I have come across a most peculiar compiler error. When I try to define a cast operator to convert from a base class to a derived class I get this error - apparently according to the help "User-defined conversions to values of a derived class are not allowed; you do not need such an operator."
    Is this as insane as it appears to be or am I missing something somewhere? Of course I need to define a cast operator, how else can the compiler know how to create a derived type from a base type?
    Any explanations appreciated.
    Dave
    Sunday, September 25, 2005 4:57 PM

Answers

  • Dave,

    I'm unclear on why you need to overload the cast operator to create a Derived object from a Base object. Could you instead give Derived a constructor that takes a Base as an argument?

    ~Tom Meschter
    Software Design Engineer, Visual C# IDE

    Tuesday, October 18, 2005 6:58 PM

All replies

  • Dave -

    given a class Base, a Derived class IS-A Base, so no conversion is necessary.

       Base b = new Derived(args);   //   b is of type Derived

    Take a look at "abstract" types and "interfaces" for the reasoning

    Tuesday, September 27, 2005 9:43 PM
  • you misunderstood the question

    Derived b = (Base)a;    // this sort of style conversion is needed

    Tuesday, October 4, 2005 5:26 PM
  • i doubt it
    Tuesday, October 4, 2005 7:47 PM
  • Peter,

    You're wrong. That's exactly what I was just trying to do.

    -Steve
    Tuesday, October 18, 2005 4:37 AM
  • Dave,

    I'm unclear on why you need to overload the cast operator to create a Derived object from a Base object. Could you instead give Derived a constructor that takes a Base as an argument?

    ~Tom Meschter
    Software Design Engineer, Visual C# IDE

    Tuesday, October 18, 2005 6:58 PM
  • Guys,

    I agree with Dave. I have the following situation. I have class A for which I overlodaded the casting operators to accept conversion to strings. So I can do things like this:

    A a = "Test";

    However, If I do this:

    object s = "Test";

    A a = s;

    I get a run-time error telling me "Unable to cast object of type System.String to type A".

    This kind of functionality, even though not frequently needed, comes very handy when you want to bind gui controls against Business Objects and you bind against the Business Object properties. This controls typically use reflection to do the binding in a way like this:

    Dim emp As New Employee

    Dim pi As PropertyInfo = emp.GetType.GetProperty("PR_Salary")

    Dim guiValue As String = "2345.45"

    pi.SetValue(emp, guiValue, Nothing) 'This will throw a run-time exception "Unable to cast ...

    emp.PR_Salary = guiValue 'this will work fine

    Dim guiObjValue As object = "2345.45"

     emp.PR_Salary = guiObjValue 'This will throw a run-time exception "Unable to cast ...

    in this example you can assume PR_Salary is of type "Currency" (a custom class) for which the casting (i.e. conversion) to an from a String is defined.

    Thanks.

     

    Wednesday, January 4, 2006 7:56 PM
  • Well, I'll ante up on this. I'm attempting to control the proliferation of type instances to conserve memory use (remember those days :D)

     I have a generic id factory with id subtypes (to have type safety on the IDs themselves - an Id can't reference an object other than the type it is an ID for - but the IDs are globaly unique across all types - and smaller than a GUID, might I add) which refers to the key collections of a set of in-memory ID dictionarys that actually enable re-use of the ID reference throughout the application (as well as referencing stuff (shh - it's a secret) in the Dictionary value object.

    So, I'm currently trying to implement a routine which will return the correct reference to the ID. Passing in the super-type as an argument on the constructor doesn't enable me to return a reference to a different object, so I get memory bloat.

    Ideally, I want to implent a conversion operator along these lines:

    // Explicit SubEntityId conversion operator

    public static explicit operator SubEntityId(EntityId e_id)

    {

       SubEntityId rc = null;

       rc = getSubEntityId(e_id); // Will find the SubEntityId in the dictionary if it is already instantiated and return the reference

       if (rc == null)

          return (new SubEntityId (e_id.value));

       return rc;

    }

    Which, in the layers above me in the code, would look like the following when creating a brand new key  (which will result in the new operator kicking in)

    SubEntityId sei = (SubEntityId) IdFactory.GetNewId();

    and the following when retrieving the value from a persisted reference (SQL, Db, etc) so that I can retrieve the reference to the existing Id, rather than duplicating it in memory and doing value comparisons everywhere...

    SubEntityId sei = (SubEntityId) GetSubEntityId( IdValue );

    And don't tell me I don't need to do this.

    Saturday, July 1, 2006 5:53 PM
  • Mike –

     

    How are you defining “saving memory”? Is it that you have limited storage for data, but unlimited storage for code? Or vice versa, maybe.

     

    When you say

     

    Passing in the super-type as an argument on the constructor doesn't enable me to return a reference to a different object,

     

    you’re absolutely correct, but I don’t follow when you add

     

    so I get memory bloat.

     

    How so?

     

    If EntityID is a class, why not use it as the sole identifier for search purposes? If SubIDA, SubIDB and SubIDC all derive from EntityID, then a property of each derived class can return the EntityID slice…

    Saturday, July 1, 2006 8:40 PM
  •  To answer your quesiton directly, I get memory bloat if I am required to replicate the ID value itself unnecessarily, rather than a reference to the value. To be clear, the size of the reference is smaller than the size of the globally unique ID value - so I keep a master list of the globally unique IDs (not the GUID implementation - smaller than that!) ... and I apply various house keeping, custom data source (list presentation) and access control algorithms to reference the ID internally under various contexts - but the referencing objects only store the reference itself - the ID is a singleton instance, as is the summary information about the object itself keyed off the ID - and object expansions of the summary objects also work off the same instance. (Infer at this point that I have many more instance references than instances themselves)

    I have implmented a non-elegant but functional workaround that uses a method off the EntityID that is type specific - e_id.ToSubEntityId() - several of these - that return the specfic type of entity id. The difficulty arises in that I want a clean explicit conversion operator to do the ID type conversion rather than a method call on the generic ID. I could alternatively write the same method on the ID factory to enable prodution of IDs of a specific type - but that is the equivalent to my current workaround, with it's utility limited to new ID creation.

    Hope that helps you to understand my concern... my worries are perhaps founded in a personal philosophy of how to write code frameworks and foundation layers - if you can do this:

    SubEntityIDinstance = EntityIdinstance.ToSubEntityID(); 

    then IMHO, you should be able to implement

    SubEntityIDinstance = (SubEntityID) EntityIdinstance;

    ... and the later is cleaner and easier than the former. In the end, all of these things boil down to SMOP - it's a Simple Matter Of Programming - and anything can be done - so I guess I'm arguing a case for the more elegant solution, particularly when publishing frameworks out of a small group to be used by a larger programming community.

    Saturday, July 1, 2006 9:42 PM
  • Terminology check: superclass = base class, subclass = derived class.

    The thing is, you can’t cast a derived type to a base type and maintain type safety.

     

          Base b = new Base();

          Derived d = new Derived();

     

          Base bIsdSliced = (Base)d;

          int baseValueFromDerived = d.BaseValue; // slice implemented

          Derived dIsbCast = (Derived)b;      //    fails

     

    So you can’t do this:

    SubEntityIDinstance = EntityIdinstance.ToSubEntityID(); 

    because EntityIdinstance can’t know about SubEntityIDinstance. Base classes are written with the idea that anyone can derive from the class.

     

    What you’re trying, if I understand correctly, will require more than a SMOP – you will need to subvert type safety.

     

    You might want to look at Interfaces in order to force some methods to be implemented in the derivees.

    Sunday, July 2, 2006 1:33 AM
  • Ah. I should have mentioned that the base class and all derived classes (superclass and subclass for those of us that date ourselves in the business - my first OO language was Simula, the pre-cursor of Smalltalk) all share a common set of interior values, so the conversion is quite simple to implement, and the subclass typing is implemented simply to ensure type safety elsewhere when passing IDs around the application and using them in various data structures.

    As mentioned, I'd prefer to implement an explict conversion operator (I'm well aware that the language can't intrinsically understand how to create the derived class without the implementation of explicit code implementing the conversion) - what I'm protesting is that C# disallows the implementation of an explicit conversion operator between the base class and the derived class.

    And as I mentioned, I have already implemented the workaround (SubEntityIDinstance = EntityIDinstance.ToSubEntityID();) - and it works fine. I just balk at it's lack of style - but since all the ID types are implemented in a single .cs file, and the generic ID factory is implemented in the same assembly, and the ToSubEntityID method is restricted to internal use, I think I can abide the conceptual impurity in the interest of gaining economy elsewhere in the upstream modules.

    Interesting discussion.

    Sunday, July 2, 2006 1:48 AM
  • Aha!

     

    Maybe yous hould loose the inheritance then and use instead the implicit operator! :)

    That should be what you are looking for :)

     

    Imlicit in one way, but explicit in the reversed direction.

    Monday, October 23, 2006 9:41 AM
  • Interesting thought. I'll need to look back and check on the code and see if there are any other constraints or things I'm doing that I haven't mentioned (been a few months now - I've moved elsewhere in the code) ... but I suspect such an approach will affect my Id management subsystem significantly. Good thinking though.

    I still maintain that the language should support symmetry in this, but (as per the Rolling Stones)... "You can't always get what you want..."

    Monday, October 23, 2006 2:19 PM