locked
How to Explicitly Convert from Derived Class to Base Class RRS feed

  • Question

  • Hello, I found a couple of posts about this topic, but they are fairly dated and I am not sure if I am asking the same question.  Essentially, I am creating a framework where I want a derived class to serialize differently than the base class, (pretty basic).

    Class Book,IXmlSerializable;
    Class Dictionary:Book
    Book myBook = new Book();

    [WebMethod]
    public Book GetDictionaryInBookFormat()
    {
       Dictionary myDictionary = LoadDictionary();
       Book myBook = (Book) myDictionary; 
       return myBook;
    }

    [WebMethod]
    public Dictionary GetDictionaryInDictionaryFormat()
    {
       Dictionary myDictionary = LoadDictionary(); 
       return myDictionary;
    }

    ---------------
    Since the "Dictionary" class overrides the WriteXml(XmlWriter writer) method of the ISerializable interface, the Dictionary base class always gets invoked.

    So, I tried to explicitly overriede the conversion operator as such, and get the compiler error.

    public static explicit operator Book(Book derivedObject)
    {
    Book result = new Book();
    result.Name = derivedObject.Name;
    result.Properties = derivedObject.Properties;
    return result;
    // code to convert from int to MyType
    } This returns with the compiler error:
    Error 1 User-defined operator cannot take an object of the enclosing type and convert to an object of the enclosing type 

     

     

    By creating a new instance of the base object, I don't have to deal with the overriden methods being invoked.

    Again, the intention is to have the base class serialize in a more general cross-compatible manner than the derived classes do, and for the webservice, (or any IXmlSerializable context) to behave differently.


    If anyone could point me in the right direction, I would appreciate it! Why is there a limitation for a conversion operator to convert to a base class, especially if what it returns is a deep copy?

    Thanks!

    • Edited by e.s. kohen Thursday, March 25, 2010 9:41 PM Cleaned up whitespace
    Wednesday, March 24, 2010 4:18 AM

Answers

  • Louis,

    Thanks again ...

    Just a couple quick comments:

    -------------------------
    Louis Said:
    -------------------------
    You can do whatever you want in a user-defined conversion, but you cannot define a conversion from or to a base class.

    -------------------------
    e.s. Response:
    -------------------------
    Is this mentioned in a C# spec or anywhere else?  I would like to understand why they made this limitation from a runtime point of view.  I don't understand why they would limit a conversion operator from returning an instance of a base class, especially a deeply copied instance.

    However, I did work around this issue by adding another level of abstraction and by using the "new" operator in the way you mentioned before.

    Class GenericBook:
    public void IXmlSerializable.WriteXml(XmlTextWriter writer)
    {
      //Write XML <Book>...</Book>
    }

    Class SpecializedBook: GenericBook
    public void new GenericBook.WriteXml(XmlTextWriter writer)
    {
      //Write schema specific XML <Dictionary>...</Dictionary>
    }

    Class Dictionary: SpecializedBook

    [WebMethod]
    public Dictionary GetDictionary()
    return new Dictionary();

    [WebMethod]
    public Book GetDictionary()
    return (Book) new Dictionary();

    This seems to solve all of the problems that I mentioned before.  I don't have to override the explicit cast operator, and the object will serialize differently based on the interface it is being accessed from.  So, I end up getting the polymorphic behavior I was looking for by using "New".  I honestly have no idea how this works with the runtime, and would love more info. 

    Anyhoo..  About the other solutions:

    -------------------------
    Louis Said:
    -------------------------
    public void WriteXml<T>() where T : BaseClass
        {
            if (typeof(T) == typeof(BaseClass))
                Console.WriteLine("Base class");
            else if (typeof(T) == typeof(DerivedClass))
            Console.WriteLine("Derived class");
        }

        public static void WriteXml(BaseClass bc)
        {
            Console.WriteLine("Base class");
        }
        public static void WriteXml(DerivedClass dc)
        {
            Console.WriteLine("Derived class");
        }

    -------------------------
    e.s. Response:
    -------------------------
    The WriteXml method is part of the IXmlSerializable interface and I cannot redefine the method signatures. 

    Thanks again for all of your help ... Though, it would still be nice to understand the explicit conversion operation limitations.  I suppose this might be one of those questions that always end with the answer "42"

    • Marked as answer by e.s. kohen Saturday, March 27, 2010 3:57 AM
    Thursday, March 25, 2010 9:38 PM
  • Is this mentioned in a C# spec or anywhere else?  I would like to understand why they made this limitation from a runtime point of view.  I don't understand why they would limit a conversion operator from returning an instance of a base class, especially a deeply copied instance.

    C# Language Specification v3.0: "it is not possible to redefine an already existing implicit or explicit conversion"

    A programmer using your class should always know when a user-defined conversion occurs without needing to inspect the class. If you could redefine existing conversions, the programmer could have a user-defined conversion taking place where the standard conversion was expected.

    • Marked as answer by e.s. kohen Saturday, March 27, 2010 3:57 AM
    Friday, March 26, 2010 2:18 AM
  •  

    Louis,

    Thanks for the reply.

    I had to smile a bit when I read the logic though. :) 

    "If you could redefine existing conversions, the programmer could have a user-defined conversion taking place where the standard conversion was expected."

    If that was a good justification, I suppose there wouldn't be any real purpose for allowing programmers to explicitly override operators. :) 

    Someone else said that it could lead to "bugs".  Got to love seeing "slippery slope" fallacies in science. 

    Honestly, I have been looking for a more concrete answer, like maybe something was happening in the runtime that could get a bit messed up. 

    The Reference to the spec is here:
    http://msdn.microsoft.com/en-us/vcsharp/aa336809.aspx

    Though, what I don't understand is what you quoted reflects "predefined" conversions.  At first, this doesn't seem to apply in my case because I haven't predefined any conversions at all.  This means that something else is defining it.

    Either way, I have the code working, so yay. :)  I have no idea why I didn't think of the "new" operator, so I appreciate the hint!

    I hope C# does delve further into polymorphism though.  I am not sure how polymorphism turned into "overloading methods", but I hope C# will progress to tackle objects being able to "behave in many different ways".

    Book myBook = new Book();

    Pages = (IBook) myBook.Length; // Returns page numbers
    ByteCount = (IBookStream) myBook.Length; // returns number of characters.
    SectionCount = (IReference) myBook.Length; // returns number of sections.

    I think Interface, or behavioral, polymorphism would be a nice feature to the language.  But I am not sure how it could work without being able to override explicit cast operators ...

    • Edited by e.s. kohen Friday, March 26, 2010 5:34 AM type-o
    • Marked as answer by e.s. kohen Saturday, March 27, 2010 3:57 AM
    Friday, March 26, 2010 5:34 AM

All replies

  • 1) I don't understand where is Dictionary and where is WriteXML()  ??
    2) public static explicit operator Book(Book derivedObject)  <-  Yes you can not convert from 'Book' to 'Book' - it doesn't make any sense (it's mot copy-constructor as in C++)

    3) If you have class that implement WriteXML() you could derive from this class and write your own implmentation of WriteXML() with  'new' keyword as 'new public void WriteXML()'


    C makes it easy to shoot yourself in the foot; C++ makes it harder, but when you do it blows your whole leg off (c) — Bjarne Stroustrup [http://www2.research.att.com/~bs/bs_faq.html#really-say-that]
    • Proposed as answer by Jasper22 Wednesday, March 24, 2010 8:19 AM
    • Unproposed as answer by Rudedog2Moderator Wednesday, March 24, 2010 2:39 PM
    • Proposed as answer by Jasper22 Wednesday, March 24, 2010 3:31 PM
    Wednesday, March 24, 2010 8:19 AM
  • 3) If you have class that implement WriteXML() you could derive from this class and write your own implmentation of WriteXML() with  'new' keyword as 'new public void WriteXML()'


    Thanks for responding!

    Well, this does make a lot of sense if you want to reuse code.  If your base class knows how to serialize itself in a generic way, and can also serialize specializations, then there is no reason to write the serialization logic again and again in classes that derive from the base.

    For example, a base class could serialize generically using a key, value pair.  But, if it knows that something that has derived from it is schema based, then it can generate a valid XML document that complies with that schema.

    For example:

    <Book>
        <Section>
            <Key>Car</Key>
            <Value>An automobile, usually with four wheels</Value>
        </Section>
    </Book>

    <Dictionary>
        <Entry>
            <Word>Car</Word>
            <Definition>An automobile, usually with four wheels</Definition>
        </Entry>
    </Dictionary>

    As you can see, with a generic mapping mechanism known by the base class, the base class can generate the first generic data file, or go as far as to create a specialized XML document.

    If you have a couple hundred derived classes, then it makes absolutely no sense to put the same exact specialized serialization logic in every class.  It makes far more sense to put both serialization algorithms in the base class to facilitate code reuse.

    I hope this makes more sense!   

    Wednesday, March 24, 2010 8:29 AM
  • You can always put the algorithm for the serialization in a completely new method like this:

     

    public class baseclass
    {
    
    public void WriteXml(XmlWriter writer)
    {
          GenericWriteXml(writer, "List", "Key", "value");
    }
    
    protected void GenericWriteXml(XmlWriter writer, string elementName, string keyName, string valueName)
    {
             // the logic to serialize here, use the respective parameters of the method to create elements with the right names.
    }
    }
    }

     

    Then in your derived class you can simply put:

    public void WriteXml(XmlWriter writer)
    {
          GenericWriteXml(writer, "Entry", "Word", "Definition");
    }
    
    Thus separating the algorithm into the base class (because all the more specific classes share the same algorithm, ad putting the parameters in the specific classes, because only the specific classes will know what these should be.
    Wednesday, March 24, 2010 9:03 AM
  • You should "favor composition over inheritance" by implementing these interfaces in an abstract base class.

    ISerializable Interface (System.Runtime.Serialization ...

     

    IDeserializationCallback Interface (System.Runtime ...

     


    Mark the best replies as answers. "Fooling computers since 1971."
    Wednesday, March 24, 2010 2:45 PM
    Moderator
  • 1) There's no logic to _not_ change serialization in derived class - so what derived class for ? If it implement the same details as base class - so may be stick with base class ?

    2) Sometimes you can call base.<function_name>()  in derived class. It's what call explicit calling of base class (example as in constructor when you write 'public MyNewDerivedClass(int SomeInt): base (SomeInt)'  <- you explicity initialize base class)


    C makes it easy to shoot yourself in the foot; C++ makes it harder, but when you do it blows your whole leg off (c) — Bjarne Stroustrup [http://www2.research.att.com/~bs/bs_faq.html#really-say-that]
    • Proposed as answer by Jasper22 Wednesday, March 24, 2010 3:31 PM
    Wednesday, March 24, 2010 3:31 PM
  • "Favor composition over inheritance."

    Mark the best replies as answers. "Fooling computers since 1971."
    Wednesday, March 24, 2010 4:08 PM
    Moderator
  • ------------------------
    Jesse Said...
    ------------------------
    Thus separating the algorithm into the base class (because all the more specific classes share the same algorithm, ad putting the parameters in the specific classes, because only the specific classes will know what these should be.

    ------------------------
    e.s. Response
    ------------------------
    The logic for serializing /all/ of the derived classess is the same...  If I copy and paste the logic into all of the derived classes, it kind of defeats the purpose of code reuse and polymorphic behavior.

    The base class, knowing its generic schema, can serialize in a way that is generic.  But, the "schema" of the derived classes is also known to the base class.  Because the base class knows of the specialized schema, it can infer the algorithm for the specific and required serializations.

    // What I am doing now to "hack" this
    [WebMethod]
    public Dictionary GetDictionary()
    {
    Dictionary dictionary = GetDictionary();
    
    dictionary.SerializationMethod = SerializationMethod.GenericSerialization;
    
    /* 
    Another serialization option is SerializationMethod.SpecializedSerialization
    The base class, in its WriteXml implementation, checks this property.
    */
    
    return dictionary;
    
    /*
    Returns:
    <Dictionary>
       <Entry> ... </Entry>
    </Dictionary>
    */
    }
    
    
    
    // What I would rather do.
    [WebMethod]
    public Book GetDictionary()
    {
    Dictionary dictionary = GetDictionary();
    
    return = (Book) dictionary;
    
    /*
    Returns:
    <Book>
       <Section> .... </Section>
    </Book>
    */
    }
    

     

    Wednesday, March 24, 2010 6:26 PM
  • I think you gave me another way to explain the problem.

    Of course, I would like the behavior in a base class, but the language doesn't seem to be letting me do this... The base class is not abstract because I want "value objects" to be represented in two different ways, the first way in a "standard" generic way... the second in a specialized way. 

    Depending on the way I access the class, I want the behavior to be different, (polymorphic).

    If I access a class from a derived interface, then I want it to behave differently than if I accessed it from a generic interface.

    Example:

    IAccount
    XmlData GetAccountData

    Account : IAccount 
    BankAccount : Account

    CookieAccount : Account


    Account account = AccountFactory.Get(AccountID);
    account.GetAccountData(); // returns <Account><Item></Item></Account>

    BankAccount account = AccountFactory.Get(AccountID);
    account.GetAccountData(); // returns <Account><Item></Item></Account>

    Again, if I can explicitly control the conversion operator, I can essentially perform a shallow copy in the process.

    Or, I could find some logic that says something like ...
    BaseClass

    WriteXml
    {
       If this class is being/has been cast to the generic version of itself, then serialize this way.

       Else, if this class is /not/ being cast into this generic type, then serialize this way.

    }

    Wednesday, March 24, 2010 6:38 PM
  • Casting does not work like that. and neither do objects stored in memory.

    I am not aware of any means by which an object graph can know how it is being accessed.  That means being self-aware enough to know whether or not it is being cast to a base type whenever it gets accessed.


    Mark the best replies as answers. "Fooling computers since 1971."
    Wednesday, March 24, 2010 6:51 PM
    Moderator
  •  

    Yes, you are right ... Casting does not work like this ...  And I am not aware of self awareness like I am talking about ... Which leads me back to my original question.

    Is there anyway I can override the default explicit and implicit cast/conversion operations so that when a cast is made, what happens is essentially a shallow copy?  I want to change the behavior of the cast because the WebService framework is unaware of the polymorphic behaviorial differences of the children and bases classes. 

    Again, the idea is for the objects to serialize in different contexts, (determined by the interface they are being accessed by...

    IDictionary: IBook

    Dictionary myDictionary;

    These two statements should behave differently:

    Serialize((IBook) myDictionary);  //Outputs <Book><Section>..</Section>
    Serialize((IDictionary) myDictionary); //Outputs <Dictionary><Entry>...</Entry></Dictionary>

    As I mentioned before, the way I am getting around this is by setting an attribute like this...
    myDictionary.SerializationMethod = SerializationMethod.Generic;
    or
    myDictionary.SerializationMethod = SerializationMethod.Specialized;

    Book: IBook, IXmlSerializable
    {
    ....

    public void WriteXml(XmlTextWriter write)
    {
       switch (SerializationMethod)
      {
       case SerializationMethod.Generic:
           SerializeGenerically(writer);
           break;
       case SerializationMethod.Specialized:
           SerializeSpecialized(writer);
           break;
       case SerializationMethod.Custom:
           throw new Exception("The Base Class WriteXml() is being invoked in error.  Your customized serialization behavior should override this method.");
           break;

      }
    }

    }

    Obviously what I want to happen is to not have to set that flag every time.  (Lots of bugs happen if not set correctly).

    Rather, something more like this:
    public void WriteXml(XmlTextWriter write)
    {
       if (this.GetType() == typeof(Book)) // But this is true for all derived types.
      {
         SerializeGenerically(writer);
      }
      else
      {
        SerializeSpecialized(writer);   }
      }
    }

    In order for this to work I would have to cast back up to the base class where the runtime isn't aware that it was a derived class before.  I need to hide its "specialness" from the runtime in order for that condition to work.

    If I do an explicit cast override, I could do this.  But, I am having issues with this.  Are there any other ways to do this? 

    Wednesday, March 24, 2010 8:31 PM
  • Casting does not work like that. and neither do objects stored in memory.

    I am not aware of any means by which an object graph can know how it is being accessed.  That means being self-aware enough to know whether or not it is being cast to a base type whenever it gets accessed.


    Mark the best replies as answers. "Fooling computers since 1971."


    Yes, you can make classes aware of how they are accessed: a non-virtual method call doesn't depend on the actual type of the object.

    class BaseClass
    {
        public void WriteXml()
        {
            Console.WriteLine("Base class");
        }
    }
    class DerivedClass : BaseClass
    {
        public new void WriteXml()
        {
            Console.WriteLine("Derived class");
        }
    }
    class TestMe
    {
        public static void Main()
        {
            DerivedClass dc = new DerivedClass();
            dc.WriteXml();
            BaseClass bc = (BaseClass)dc;
            bc.WriteXml();
        }
    }
    Thursday, March 25, 2010 12:01 AM
  • Louis,

    Thank you for the reply.

    However, the approach you mentioned requires that every derived class have the serialization logic placed within them, (thousands of derived classes).

    But, the serialization logic works differently based on the schema of the objects, and is generic enough to be placed one time in the base class.

    However, it is a requirement that an object can be serialized in a "Universal" way, as well as be serialized in its custom way, determined by the way it is being accessed.

    Again:
    Book myBook = new Book();
    Dictionary myDictionary = new Dictionary();

    Both of these should serialize the exact same way, generically:

    Serialize(myBook);
    Serialize((Book) myDictionary);

    Output:
    <Book>
       <Section></Section>
    </Book>

    And both of these should serialize in the same exact specialized way:
    Serialize((Dictionary) myBook);
    Serialize(myDictionary);

    Output:
    <Dictionary>
       <Entry></Entry>
    </Dictionary>

    Thanks for the idea of using the "new" keyword.  But, it still creates the requirement that consumers of this API put Serialization algorithms into their own classes.  The base class must be able to handle this.

    Again, my "hack" solution is this:
    Dictionary myDictionary = new Dictionary();
    myDictionary.SerializationMethod = SerializationMethod.Generic;
    Serialize(myDictionary);

    Outputs
    <Book><Section></Section></Book>

    and ----

    Dictionary myDictionary = new Dictionary();
    myDictionary.SerializationMethod = SerializationMethod.Specialized;
    Serialize(myDictionary);

    Outputs
    <Dictionary><Entry></Entry></Dictionary>

    I do not want consumers to have to set the SerializationMethod, or to have to write their own WriteXml logic.

    This is all that should be required:

    [WebMethod]
    Book GetDictionary()
    {
       return (Book) new Dictionary();
    }

    [WebMethod]
    Dictionary GetDictionary()
    {
       return new Dictionary();
    }

    Again, thanks for the help.  Your "new" suggestion actually gave me an idea how to solve another problem! :)

    Again, the question is, is there a way I could convert explicitly from a derived class to a base class, or vice versa by overloading the explicit conversation operator?

    Can I have the explicit conversion operator just do a shallow copy?  Or is there another way of doing this?

    Thanks again!

    Thursday, March 25, 2010 1:05 AM
  • However, the approach you mentioned requires that every derived class have the serialization logic placed within them, (thousands of derived classes).

    Using non-virtual methods is the only way to do something based on the static type of an expression.

    However, it is a requirement that an object can be serialized in a "Universal" way, as well as be serialized in its custom way, determined by the way it is being accessed.

    Again:
    Book myBook = new Book();
    Dictionary myDictionary = new Dictionary();

    Both of these should serialize the exact same way, generically:

    Serialize(myBook);
    Serialize((Book) myDictionary);

    Output:
    <Book>
       <Section></Section>
    </Book>

    And both of these should serialize in the same exact specialized way:
    Serialize((Dictionary) myBook);
    Serialize(myDictionary);

    Output:
    <Dictionary>
       <Entry></Entry>
    </Dictionary>

    That's what the problem I was addressing. Each class need to know how to serialize itself for this to work.

    Serialize((Dictionary) myBook);

    This works only if myBook is an instance of Dictionary.

    Again, the question is, is there a way I could convert explicitly from a derived class to a base class, or vice versa by overloading the explicit conversation operator?

    Can I have the explicit conversion operator just do a shallow copy?  Or is there another way of doing this?

    You can do whatever you want in a user-defined conversion, but you cannot define a conversion from or to a base class.

    You can try something like this:

    class BaseClass
    {
        public static void WriteXml(BaseClass bc)
        {
            Console.WriteLine("Base class");
        }
        public static void WriteXml(DerivedClass dc)
        {
            Console.WriteLine("Derived class");
        }
    }
    class DerivedClass : BaseClass
    {
    }
    class TestMe
    {
        public static void Main()
        {
            DerivedClass dc = new DerivedClass();
            BaseClass.WriteXml(bc);
            BaseClass bc = (BaseClass)dc;
            BaseClass.WriteXml(dc);
        }
    }
    

    or

    class BaseClass
    {
        public void WriteXml<T>() where T : BaseClass
        {
            if (typeof(T) == typeof(BaseClass))
                Console.WriteLine("Base class");
            else if (typeof(T) == typeof(DerivedClass))
            Console.WriteLine("Derived class");
        }
    }
    class DerivedClass : BaseClass
    {
    }
    class TestMe
    {
        public static void xMain()
        {
            DerivedClass dc = new DerivedClass();
            dc.WriteXml<DerivedClass>();
            dc.WriteXml<BaseClass>();
        }
    }
    Thursday, March 25, 2010 6:46 PM
  • Louis,

    Thanks again ...

    Just a couple quick comments:

    -------------------------
    Louis Said:
    -------------------------
    You can do whatever you want in a user-defined conversion, but you cannot define a conversion from or to a base class.

    -------------------------
    e.s. Response:
    -------------------------
    Is this mentioned in a C# spec or anywhere else?  I would like to understand why they made this limitation from a runtime point of view.  I don't understand why they would limit a conversion operator from returning an instance of a base class, especially a deeply copied instance.

    However, I did work around this issue by adding another level of abstraction and by using the "new" operator in the way you mentioned before.

    Class GenericBook:
    public void IXmlSerializable.WriteXml(XmlTextWriter writer)
    {
      //Write XML <Book>...</Book>
    }

    Class SpecializedBook: GenericBook
    public void new GenericBook.WriteXml(XmlTextWriter writer)
    {
      //Write schema specific XML <Dictionary>...</Dictionary>
    }

    Class Dictionary: SpecializedBook

    [WebMethod]
    public Dictionary GetDictionary()
    return new Dictionary();

    [WebMethod]
    public Book GetDictionary()
    return (Book) new Dictionary();

    This seems to solve all of the problems that I mentioned before.  I don't have to override the explicit cast operator, and the object will serialize differently based on the interface it is being accessed from.  So, I end up getting the polymorphic behavior I was looking for by using "New".  I honestly have no idea how this works with the runtime, and would love more info. 

    Anyhoo..  About the other solutions:

    -------------------------
    Louis Said:
    -------------------------
    public void WriteXml<T>() where T : BaseClass
        {
            if (typeof(T) == typeof(BaseClass))
                Console.WriteLine("Base class");
            else if (typeof(T) == typeof(DerivedClass))
            Console.WriteLine("Derived class");
        }

        public static void WriteXml(BaseClass bc)
        {
            Console.WriteLine("Base class");
        }
        public static void WriteXml(DerivedClass dc)
        {
            Console.WriteLine("Derived class");
        }

    -------------------------
    e.s. Response:
    -------------------------
    The WriteXml method is part of the IXmlSerializable interface and I cannot redefine the method signatures. 

    Thanks again for all of your help ... Though, it would still be nice to understand the explicit conversion operation limitations.  I suppose this might be one of those questions that always end with the answer "42"

    Thursday, March 25, 2010 9:38 PM
  • Louis,

    Thanks again ...

    Just a couple quick comments:

    -------------------------
    Louis Said:
    -------------------------
    You can do whatever you want in a user-defined conversion, but you cannot define a conversion from or to a base class.

    -------------------------
    e.s. Response:
    -------------------------
    Is this mentioned in a C# spec or anywhere else?  I would like to understand why they made this limitation from a runtime point of view.  I don't understand why they would limit a conversion operator from returning an instance of a base class, especially a deeply copied instance.

    However, I did work around this issue by adding another level of abstraction and by using the "new" operator in the way you mentioned before.

    Class GenericBook:
    public void IXmlSerializable.WriteXml(XmlTextWriter writer)
    {
      //Write XML <Book>...</Book>
    }

    Class SpecializedBook: GenericBook
    public void new GenericBook.WriteXml(XmlTextWriter writer)
    {
      //Write schema specific XML <Dictionary>...</Dictionary>
    }

    Class Dictionary: SpecializedBook

    [WebMethod]
    public Dictionary GetDictionary()
    return new Dictionary();

    [WebMethod]
    public Book GetDictionary()
    return (Book) new Dictionary();

    This seems to solve all of the problems that I mentioned before.  I don't have to override the explicit cast operator, and the object will serialize differently based on the interface it is being accessed from.  So, I end up getting the polymorphic behavior I was looking for by using "New".  I honestly have no idea how this works with the runtime, and would love more info. 

    Anyhoo..  About the other solutions:

    -------------------------
    Louis Said:
    -------------------------
    public void WriteXml<T>() where T : BaseClass
        {
            if (typeof(T) == typeof(BaseClass))
                Console.WriteLine("Base class");
            else if (typeof(T) == typeof(DerivedClass))
            Console.WriteLine("Derived class");
        }

        public static void WriteXml(BaseClass bc)
        {
            Console.WriteLine("Base class");
        }
        public static void WriteXml(DerivedClass dc)
        {
            Console.WriteLine("Derived class");
        }

    -------------------------
    e.s. Response:
    -------------------------
    The WriteXml method is part of the IXmlSerializable interface and I cannot redefine the method signatures. 

    Thanks again for all of your help ... Though, it would still be nice to understand the explicit conversion operation limitations.  I suppose this might be one of those questions that always end with the answer "42"

    • Marked as answer by e.s. kohen Saturday, March 27, 2010 3:57 AM
    Thursday, March 25, 2010 9:38 PM
  • Is this mentioned in a C# spec or anywhere else?  I would like to understand why they made this limitation from a runtime point of view.  I don't understand why they would limit a conversion operator from returning an instance of a base class, especially a deeply copied instance.

    C# Language Specification v3.0: "it is not possible to redefine an already existing implicit or explicit conversion"

    A programmer using your class should always know when a user-defined conversion occurs without needing to inspect the class. If you could redefine existing conversions, the programmer could have a user-defined conversion taking place where the standard conversion was expected.

    • Marked as answer by e.s. kohen Saturday, March 27, 2010 3:57 AM
    Friday, March 26, 2010 2:18 AM
  •  

    Louis,

    Thanks for the reply.

    I had to smile a bit when I read the logic though. :) 

    "If you could redefine existing conversions, the programmer could have a user-defined conversion taking place where the standard conversion was expected."

    If that was a good justification, I suppose there wouldn't be any real purpose for allowing programmers to explicitly override operators. :) 

    Someone else said that it could lead to "bugs".  Got to love seeing "slippery slope" fallacies in science. 

    Honestly, I have been looking for a more concrete answer, like maybe something was happening in the runtime that could get a bit messed up. 

    The Reference to the spec is here:
    http://msdn.microsoft.com/en-us/vcsharp/aa336809.aspx

    Though, what I don't understand is what you quoted reflects "predefined" conversions.  At first, this doesn't seem to apply in my case because I haven't predefined any conversions at all.  This means that something else is defining it.

    Either way, I have the code working, so yay. :)  I have no idea why I didn't think of the "new" operator, so I appreciate the hint!

    I hope C# does delve further into polymorphism though.  I am not sure how polymorphism turned into "overloading methods", but I hope C# will progress to tackle objects being able to "behave in many different ways".

    Book myBook = new Book();

    Pages = (IBook) myBook.Length; // Returns page numbers
    ByteCount = (IBookStream) myBook.Length; // returns number of characters.
    SectionCount = (IReference) myBook.Length; // returns number of sections.

    I think Interface, or behavioral, polymorphism would be a nice feature to the language.  But I am not sure how it could work without being able to override explicit cast operators ...

    • Edited by e.s. kohen Friday, March 26, 2010 5:34 AM type-o
    • Marked as answer by e.s. kohen Saturday, March 27, 2010 3:57 AM
    Friday, March 26, 2010 5:34 AM
  • I had to smile a bit when I read the logic though. :) 

    "If you could redefine existing conversions, the programmer could have a user-defined conversion taking place where the standard conversion was expected."

    If that was a good justification, I suppose there wouldn't be any real purpose for allowing programmers to explicitly override operators. :) 


    I don't see what makes you smile. When using an operator, or explicilty or implicitly casting an object from a type to another, the programmer knows that the operator exists or the conversion exists. If you could redefine them, the programmer could be using them without knowing it.

    Suppose you could redefine the predefined conversion from derived to base (I know you didn't predefined it, it is predefined by C#).

    When I do something like this:

    object o = new SomeClass();

    how am I supposed to know what happens? Is it going to put a reference to the newly instantiated object into o? Or is it going to call an user-defined conversion? I should not have to know all the methods of SomeClass to write that line in my code.

    Friday, March 26, 2010 10:48 PM
  •  

    I understand that the consumer of the API won't know what is happening when the conversion is taking place, (unless it is documented).  But, this is the case anytime someone overrides operator behavior.  They don't know what is going on underneath.  For example, if you override the "+" operator ... Unless it is well documented, the consumer won't know what is going on.

    To say that this is an issue in only one case, but not in all of the others isn't exactly "consistent".  Anyhoo... I understand that there are business requirements behind this now.  I asked around and this cannot be changed because of backward compatibility issues.  I wasn't trying to be offensive, I was just saying that it isn't a "scientifically valid" argument.  Assuming that something cannot be done, (like making progress in some "x"), because people are not smart enough... well..  The invalidity of this argument is illustrated perfectly in politics. 

    Anyhoo... I forgot to close this thread... You did answer it with the quote from the C# 3.0 spec.  Though, I am not sure where the the explicit conversion to a base class is "predefined".  I am guessing it is something that the Runtime is doing or the compiler.  It would be nice to overload it.

    Saturday, March 27, 2010 3:57 AM
  • The programmer will not use the + operator without knowing it has been defined. I don't see how this contradicts my point.

    It is a valid argument. Redefining a predefined operator leads to the same problem whatever the operator.

    The implicit conversion to base class is predefined by design. You can see it is because you don't need to define it to write this:

    object o = new MyObject();

    Sunday, March 28, 2010 4:43 AM
  • The programmer will not use the + operator without knowing it has been defined. I don't see how this contradicts my point.

    It is a valid argument. Redefining a predefined operator leads to the same problem whatever the operator.

    The implicit conversion to base class is predefined by design. You can see it is because you don't need to define it to write this:

    object o = new MyObject();

    Sunday, March 28, 2010 4:44 AM
  • Since you seems not to understand why it's logic, let's try a simple question.

    Do you think this:

    (object)myObject == (object)myObject

    should:

    1) always return true

    2) always return false

    3) it depends

    Sunday, March 28, 2010 4:59 AM
  •  

    Well, I am not certain if this was intended as a trick question or not, but I suppose it would depend on how the == operator was overriden.  :) Unfortunately, from your code, I cannot tell... which is the point I am trying to make.  The editor or some other mechanism needs to let developers know if something has been overriden.  But the short answer is yes. ...  But the long answer is, this scenario doesn't really apply to this problem.

    But, if someone had overriden the == operator in the code above, you would have no idea.  One really handy way of doing this would be to allow people to use compiler directives, (this would be awesome for simulating "throws" clauses instead of encountering exceptions haphazardly).

    http://msdn.microsoft.com/en-us/library/ms173147(VS.80).aspx

    "By default, the operator == tests for reference equality by determining if two references indicate the same object ..."

    If this behavior had been overriden, you would not be able to tell.

    For example, in my case, if I wanted to override the == operator, I would have overriden the == operator to determine the equality of the "data" within my classes, not the class type, or the equality of the behavior.  If the data was all the same, then I would know if the instances were equal or not. 

    This scenario happens all the time in data driven applications.  In the System are two instances of the same persisted object, and the System needs to determine if something has been updated or not.  Even though the classes are in different memory locations, the Data in these classes may be the same.

    In business rule applications, you might have two instances of the same data, but different operations, (polymorphic behavior) needs to be executed, (for example Book logic is different from Dictionary logic, but the underlying data is the same, (in this case). The classes are still "different" even though they have the same data, because they have different behavior.  This is analaogous to a shell game, you pass the same value object into different wrapping classes, anticipating different behavior.  This is more commonly seen as the same data file de-serializing into two different binary classes.

    Again, the argument you presented was that when you override behavior: "A programmer using your class should always know when a user-defined conversion occurs without needing to inspect the class."

    By definition, whenever anything is overriden, this is always the case.  If you override the behavior, a programmer using the class would NOT always know the behavior, because it would be acting in an unexpected manner as a result of being overridden.  This is true if you override behavior between derived classes, or completely different classes.

    I will put this a different way ...  If I write MyClass B = (MyClass) new YourClass();  ...
    The programmer has no way of telling, (by the code alone), if the logic has been overriden.

    So, to answer your question ...

    Do you think this:
    (object)myObject == (object)myObject

    should:
    1) always return true
    2) always return false
    3) it depends

    ((IObject)myObject == (IObject)thatObject)
    // should return true if the implementing methods, properties and events of both classes are the same.
    // i.e., the methods, either in the DLL or memory are in the same location. 
    // Ideally this would return true if the "Signature Table" (analagous to a truth table in logic) were identical.
    // For any given parameter set, the results are always the same.  *Kinda farfetched to implement now. ..
    // "new" keywords would probably help to resolve this, also the location and context of virtual and override keywords. ..

    (Object)myObject == (ThatObject)thatObject
    //Returns true if the value being wrapped is the same.  A reference to the shell game above that is based on the value object pattern.

    (Object)myObject == (Object)thatObject
    // Returns true if the memory references are the same

    So, according to this logic, the answer to your question would apply to the third scenario, and result in true.  My problem would fall under the first two scenarios.

    I have a feeling this conversation went from a practical, "how can I override something to solve my problem", "It's impossible" to ... The Ponderous Ponders of the Theoretical and Philophical Disputations of the Prolific Potential of C#" ...

    Not really sure if you really want to get into this here. :) But beware of the random injection of desperate pleas for C# compiler directives to help identify when exceptions /could/ be thrown, (or some other such solution).  :)  Sorry, just another of those "things"...

    I really do appreciate your thoughtfulness and consideration. 

    e

    p.s. Logical Proof that Explanation was /Logically/ Invalid.  Though, I do see several business requirements why this behavior is in place.  But I would prefer just to call it a "business decision" rather than a scientific one.  I hope this illustrates why it /appears/ to be an unscientific explanation.  I am not trying to be ornerous here, really.  It appears as though that how I see it as a logically invalid explanation is not readily apparent... So, I am just putting it here for clarification. 

    1. A Programmer should not need to inspect a class or documentation to determine if a User defined conversion takes place.
    2. Pre-Defined Conversions do not always meet developer and problem requirements
    3. It is necessary to permit User Defined Conversions
    4. User Defined Conversions are not Pre-defined, their behavior is not predefined.
    5. A Programmer would have to inspect a class to determine how User Defined Conversions are taking place, since they are not predefined.
    6. But this contradicts the first rule ... IP 1 & 6
    • Edited by e.s. kohen Sunday, March 28, 2010 4:51 PM Added Logical Proof.
    Sunday, March 28, 2010 4:27 PM
  • With the rule that you cannot redefine predefined operators or conversions, you never need to know what is defined for correctly using predefined operators because you know they cannot be redefined. Of course, you need to know what is defined in order to use user-defined operators because if you don't know they exist, then you don't use them.

    Sunday, March 28, 2010 9:28 PM
  • With the rule that you cannot redefine predefined operators or conversions, you never need to know what is defined for correctly using predefined operators because you know they cannot be redefined. Of course, you need to know what is defined in order to use user-defined operators because if you don't know they exist, then you don't use them.

    Sunday, March 28, 2010 9:29 PM
  • That was extremely awesome.  :D  I am not sure if I have seen someone use "define" that many times at one time! :)

    So, I think we agree, ... *I think.  Essentially, there are already unknowns in how currently predefined operations ... operate.  So, saying "adding more unknowns to existing unknowns will add too much additional complexity" is too loosely defined to be meaningful. 

    I think C# should give developers enough rope to shoot themselves, or enough stones to make a great work of art.  It is illogical to make some constraint in one place, but not to make those same constraints in other places.

    Either way, it sounds like this needs to be made a little clearer and consistent.

    Though, I really think "pre-defined" is a bad term.  Because I think you CAN override predefined operators if those definitions were defined by developers... But I think there are "System" defined conversions, like converting from base class to derived class and vice versa. 

    It would be nice for a little tooltip to pop up when you are using an operator to inform the developer what kind of conversion is occuring, (pointer, structure, value, behavior, etc), if it is overriden, and the reference to the assembly/method/class where the logic resides. 

    That might help clear up the ambiguity.

    But, I think for any of this to happen, there has to be more than implicit and explicit conversion types permitted.  Explicit and Implicit memory conversions, explicit and implicit value conversions, etc.

    I think the subtype of conversion could be determined by how the conversion is taking place, DerivedObject to BaseObject imply one thing, BaseObject to DerivedObject, another, Interface to same Interface, Interface to different Interface, etc etc.

    That would be very cool. :)  And, I think, fairly easy to implement.  I wonder if I could go back to MSFT and write something up and get it in the spec!  Woot! 

    Though, I would probably have to add something to deal with allowing developers to see what exceptions could possibly be thrown, (that alone is a proof that totally contradicts any argument that says knowing what is going on should be apparent).  I totally agree that what is happening should be apparent, and its a great ideal... So, MSFT should apply it to exception handling! :)  (Just to be consistent.) 

    Ahem.

    Sunday, March 28, 2010 10:00 PM
  • There is no "unknowns". All standard conversions (maybe you prefer the term "standard") are known. In particular, implicit conversions to base class and explicit conversions from base class. There is no secret about how they work. Conversion to base does nothing. Conversion from base is just a check against the target type. If there is something you don't know, don't suppose nobody knows it. Just ask.

    All constraints on operators are the same, whatever the operator: at least one of the operands must be the enclosing type, you cannot redefine an already existing operator. It is clear and consistent.

    You didn't proove anything about the predictability of language-defined constructs. When you use a method, of course you need to read its documentation, including what exceptions can be thrown. But you shouldn't need to read the documentation of anything (other than the language specification) to do a language-defined operation.

    Monday, March 29, 2010 2:33 AM
  • I think maybe we have killed this topic, because we are going around in circles and talking about two different things.

    Yes, the current mechanism for overriding operators may be consistent,(personally I don't think so as a cast override does not permit base to derived logic, but the == does),  But this is not the consistency I was talking about.

    1. There absolutely is unknown behavior that occurs when people ovveride operators, (by definition).  This behavior cannot be known unless someone inspects the base class or reads the documentation.  This is what is not consistent with the principle that you mentioned that a "Developer should not have to inspect a base class to determine if a User defined conversion is taking place.  User defined conversions are already taking place in frameworks that developers do not know are "User Defined".  Here is a great example of this:

     private class BookBaseClass
            {
                public int Length;
                // Equality operator. Returns dbNull if either operand is dbNull, 
                // otherwise returns dbTrue or dbFalse:                    
            }
    
            private class Dictionary : BookBaseClass
            {
                public static bool operator ==(BookBaseClass first, Dictionary second)
                {
                    return first.Length == second.Length ? true : false;
                }
    
                public static bool operator !=(BookBaseClass first, Dictionary second)
                {
                    return first.Length != second.Length ? true : false;
                }
            }
    
            private void TestThis()
            {
                BookBaseClass book = new BookBaseClass();
                Dictionary dictionary = new Dictionary();
    
                if (book == dictionary)
                {
                }
            }

    2. Of course we shouldn't have to read documentation more than a handful of times to understand a language defined operation.  But this has nothing to do with THIS conversation.  This entire thread is about how to OVERRIDE a language-defined operation.  When this occurs, there is certainly the expectation that there needs to be documentation.  So, saying that certain overrides should not be permitted, (explicit casts from base class to derived classes) in order to make sure that people don't have to read documentation, well ... its a bit circular and internally contradictory.  My "proof" was not to prove anything about predictability; but to prove that it wasn't a logically valid argument, (which it does proof from a pure logic point of view), and it is an argument that leads to inconsistency.  To say that a feature cannot be permitted because it would required someone to examine classes in more detail would imply that overriding anything would not be permitted.  Therefore, the argument is "reduced to absurdity", really quick. 

    But, we have beat this conversation to death.  I was asking about the reasons why something is not permitted in the language when it would seem to go without saying that it should be.  You gave a reason why it is not permitted, "Because it would require developers to inspect a class and consult the documentation".

    I get that.  Really.  From a business point of view, it makes some sense.  I just wish this same justification was applied to other business decisions in the C# spec, (like not providing some language feature to allow developers to view what is being thrown at edit/compile time).

    So, I guess I have to agree to disagree with you.  Though, we did answer the question a long long time ago. :)


    P.S. Just out of ponderous ponderousness, I think both points of view are represented fairly well in this article.  It would be cool to see a PM run with this and do some community Q&A.  If this limitation was removed, there is a great deal of flexibility that developers would have implementing different patterns.
    • Edited by e.s. kohen Monday, March 29, 2010 5:36 PM Added P.S.
    Monday, March 29, 2010 5:33 PM
  • Interesting read.  If developers could "OVERRIDE a language-defined operation " then you wouldn't have a language anymore.

    Mark the best replies as answers. "Fooling computers since 1971."
    Monday, March 29, 2010 5:42 PM
    Moderator
  • I think you talked about that equality operator in an earlier post but I didn't understand it at that time.

    I now see that I was wrong. I totally forgot the == and != operators and misread the sentence in chapter 7.2.2: "it is not possible for a user-defined operator to have the same signature as a predefined operator."

    So, I was wrong about the scope of the restriction: "it is not possible to redefine an already existing implicit or explicit conversion." And this only applies to conversions.

    Monday, March 29, 2010 6:01 PM

  • Book myBook = new Book();

    Pages = (IBook) myBook.Length; // Returns page numbers
    ByteCount = (IBookStream) myBook.Length; // returns number of characters.
    SectionCount = (IReference) myBook.Length; // returns number of sections.


        enum CookedChickenStyle
        {
            Fried,
            Baked,
            Grilled,
        }
        
        public interface IChickenPart
        {
            string Name
            {
                get;
                set;
            }
        }
        interface IChicken
        {
        }
        public class ChickenPart : IChickenPart
        {
            public ChickenPart()
            {
                this.Name = "ChickenPart";
            }
            public string Name
            {
                get;
                set;
            }
        }
        class ChickenWing : ChickenPart
        {
            public ChickenWing()
            {
                this.Name = "Wing";
            }
        }
        class ChickenLeg : ChickenPart
        {
            public ChickenLeg()
            {
                this.Name = "Leg";
            }
        }
        class ChickenBreast : ChickenPart
        {
            public ChickenBreast()
            {
                this.Name = "Breast";
            }
        }
        class ChickenThigh : ChickenPart
        {
            public ChickenThigh()
            {
                this.Name = "Thigh";
            }
        }
    
        
        class Chicken : List<IChickenPart>, IChicken 
        {
            public Chicken()
            {
                this.Add(new ChickenWing());
                this.Add(new ChickenBreast());
                this.Add(new ChickenLeg());
                this.Add(new ChickenThigh());
                //
                this.Add(new ChickenWing());
                this.Add(new ChickenBreast());
                this.Add(new ChickenLeg());
                this.Add(new ChickenThigh());
                //
            }
            public Chicken(List<IChickenPart> parts)
            {
                this.AddRange(parts);
            }
            public List<U> GetTypesOf<U>() where U : IChickenPart, new()
            {
                List<U> result = new List<U>();
                foreach (IChickenPart t in this)
                {
                    switch (t.GetType() == typeof(U))
                    {
                        case true:
                            U obj = (U)t;
                            result.Add(obj);
                            break;
                        case false:
                            if (typeof(U) == typeof(ChickenPart))
                            {
                                U task = (U)t;
                                result.Add(task);
                            }
                            break;
                        default:
                            break;
                    }
                }
                return result;
            }
            public static List<U> GetTypes<U>(Chicken chicken) where U : IChickenPart, new()
            {
                return chicken.GetTypesOf<U>();
            }
            
        }
    
        class ChickenTester
        {
            Chicken chicken;
            public ChickenTester()
            {            
                chicken = new Chicken();
                return;
            }
    
            public void EatChicken<T>() where T : ChickenPart, new() // curios compile error here
            {
                List<T> thighs = chicken.GetTypesOf<T>();
                foreach (IChickenPart wing in thighs)
                {
                    Console.WriteLine(wing.Name);
                }
                return;
            }
        }

    You can do that with classes, not interfaces.

    Mark the best replies as answers. "Fooling computers since 1971."
    Monday, March 29, 2010 6:12 PM
    Moderator
  •         static void Main(string[] args)
            {
                //TestFruit();
                TestChicken();
                Console.ReadLine();
            }
    
            private static void TestChicken()
            {
                ChickenTester tester = new ChickenTester();
                tester.EatChicken<ChickenBreast>();
                return;
            }


    Mark the best replies as answers. "Fooling computers since 1971."
    Monday, March 29, 2010 6:14 PM
    Moderator
  • I started poking around with this ...  And I tried to override an already explicit conversion.  Interestingly enough ...  I got a completely different error.

    Error 2 User-defined conversion must convert to or from the enclosing type ...

    This restriction alone is enough to ensure that something is not permitted to be overriden if it has been defined already.

    So, if this wasn't the case... A person could explicitly override something, then another person override their override, etc.  I can see how this could get very confusing, and why this limitation is nice.

    Then again, we override methods that override others that override others, ... all the time.  But the handly dandy thing with methods is that you have these awesome tooltips to let you know what is going on, Summary comments, Result comments, etc.  Unfortunately, even if you comment your explicit conversion to death, the code editor is a little non-cooperative at won't let you see the tooltip. :(

     public class BaseClass
            {
                public int length;
    
                /// <summary>
                /// This is a test
                /// </summary>
                /// <param name="i">The value to convert from.</param>
                /// <returns>A new BaseClass</returns>
                public static explicit operator BaseClass(int i)
                {
                    BaseClass result = new BaseClass();
                    return result;
                }
            
            }
    
            public class DerivedClass : BaseClass
            {
                private void Test()
                {
                    BaseClass test = (BaseClass) 5;
                }
            }
    Monday, March 29, 2010 10:21 PM
  •  RudeDog,

    There are many different language specified operations that can be changed in C#.  That is the whole point of the "override" keyword, and the ability to override the default behavior of operations.  For example, if you don't want == to just compare pointer values, you can have it compare the internal values of those objects for equality.  So, it is definitely useful.

    Though, what I think Louis is getting at is something different which leads to code eventually obfuscating itself to the point where it is unusable...  There are several legacy products with backwards compatible requirements that I could point to with some "interestingly circular" dependencies... *hack hack.  The idea is how do you help stop that from happening in some meaningful way. ...

    The problem is that programming languages are related to language, not math, and both language and math related to logic.  And as an "organic" construct, programming languages, like any other language, evolve into indredible results while having the ability to shoot itself in the foot.

    So, I really think we kinda went to far into the metaphysical here... sigh.  Anyhoo.  Its definitely a dead topic.  Wish we could push some magical "close" button on it. :)  That way I won't get myself into too much more trouble. :(

    • Edited by e.s. kohen Monday, March 29, 2010 10:30 PM Forgot who I was writing it to! Sorry.
    Monday, March 29, 2010 10:29 PM