TheSwamp

Code Red => .NET => Topic started by: Draftek on November 28, 2007, 10:09:25 AM

Title: serialize collectionBase
Post by: Draftek on November 28, 2007, 10:09:25 AM
I need a strongly typed collection of an object I'm building. I derive from collectionbase and all is good except I cannot seem to serialize the collection.

Am I going to have to implement some serializing interfaces?
Title: Re: serialize collectionBase
Post by: Glenn R on November 28, 2007, 10:19:01 AM
Code?
Title: Re: serialize collectionBase
Post by: Glenn R on November 28, 2007, 10:20:34 AM
Also, what version of AutoCAD and the framework?
Title: Re: serialize collectionBase
Post by: Kerry on November 28, 2007, 10:33:09 AM
The last paragraph of this is 'interesting' ..
http://www.mattberther.com/2004/09/05/implementing-collectionbase/
Title: Re: serialize collectionBase
Post by: Draftek on November 28, 2007, 10:33:37 AM
The object:
Code: [Select]
[Serializable]
    public enum LiteType
    {
        Row,
        Col,
        Main
    }
    /// <summary>
    /// Container for the dlo lite object
    /// </summary>

    [XmlRootAttribute("Lite", Namespace = "", IsNullable = false)]
    public class cLite
    {
        #region private members

        private cLite m_parentLite = null;
        private cLites m_childLites;
        private string m_Name = "";
        private LiteType m_liteType;
        private double m_Width = 0;
        private double m_Height = 0;
        private double m_SillOffset = 0;
       
        #endregion

        #region public members
        // the parent lite or null if this is the root note
        [XmlElementAttribute("parentLite", typeof(cLite))]
        public cLite ParentLite
        {
            get { return m_parentLite; }
            set { m_parentLite = value; }
        }

        // the name string
        [XmlElementAttribute("Name")]
        public string Name
        {
            get { return m_Name; }
            set { m_Name = value; }
        }
        // the child lites collection
        [XmlArray("childLites"),
        XmlArrayItem("childLite", typeof(cLite))]
        public cLites ChildLites
        {
            get { return m_childLites; }
            set { m_childLites = value; }
        }

        [XmlElementAttribute("LiteType", typeof(LiteType))]
        public LiteType liteType
        {
            get { return m_liteType; }
            set { m_liteType = value; }
        }

        [XmlElementAttribute("Width")]
        public double Width
        {
            get { return m_Width; }
            set { m_Width = value; }
        }
        [XmlElementAttribute("Height")]
        public double Height
        {
            get { return m_Height; }
            set { m_Height = value; }
        }

        // the offset of the bottom of the lite - this is used so we can drop
        // the jamb members for a door that would run down to the floor, ignoring
        // any sill gap
        // These would only be used in the vertical sense of the primary children
        // basically the initial rows of the mark
        [XmlElementAttribute("SillOffset")]
        public double SillOffset
        {
            get { return m_SillOffset; }
            set { m_SillOffset = value; }
        }

        #endregion
        // default constructor
        public cLite() :this("No Name", 0, 0, LiteType.Main)
        {
           // default constructor calls the other one
        }
        // constructor to use
        public cLite(string name, double Width, double Height, LiteType lType)
        {
            m_Name = name;
            m_Width = Width;
            m_Height = Height;
            m_liteType = lType;
            m_childLites = new cLites(this);
        }
    }
The collection:
Code: [Select]
// this is basically the child lites collection
    [Serializable]
    public class cLites :CollectionBase
    {

        // constructor - when the collection is created, you need a parent lite
        // to add to all of the children created from the add method
        public cLites(cLite parent)
        {
            m_parentLite = parent;
        }
        #region private members
        // parent lite
        private cLite m_parentLite;
        #endregion

        #region public Members
        [XmlElementAttribute("parentLite", typeof(cLite))]
        public cLite ParentLite
        {
            get { return m_parentLite; }
            set { m_parentLite = value; }
        }
        #endregion
        // the collection stuff
        public int Add(cLite child)
        {
            child.ParentLite = m_parentLite;
            return List.Add(child);
        }
        public void Remove(cLite child)
        {
            List.Remove(child);
           
        }
        public void Insert(int index, cLite child)
        {
            List.Insert(index, child);
        }
        public cLite this[int index]
        {
            get { return (cLite)List[index]; }
            set { List[index] = value; }
        }

    }
Good point on the framework - 2.0
No autocad required
Title: Re: serialize collectionBase
Post by: Draftek on November 28, 2007, 10:39:05 AM
I stumbled on a workaround - wrapping the collection and then serializing the wrapper. It works but I don't know. Apparently there is a problem with the IList interface and serialization.
Title: Re: serialize collectionBase
Post by: Draftek on November 28, 2007, 10:41:02 AM
Sorry Kerry, didn't see your post. I'm not sure how that will help my case since I need an object.
Title: Re: serialize collectionBase
Post by: Glenn R on November 28, 2007, 10:46:47 AM
Any reason why you're not using generics then, if it's framework v2?
Title: Re: serialize collectionBase
Post by: sinc on November 28, 2007, 11:47:07 AM
That code looks like it has some nasty traps possible.

That whole thing where the collection has a "parent" property, with getter and setter, but then each individual "Lite" also has a parent...  That sounds nasty to me.  What happens if someone changes the parent Lite for the collection after a bunch of Lites are added?

And I too would recommend that you use generics instead.  The old List needs to box/unbox the elements inside it every time you do something, which results in a performance hit (although it's possible the hit isn't big enough to really notice).

And out of curiosity, what is a "Lite", anyway, besides a type of beer? :-)   Looks like it has something to do with doors, but I've never heard the term...
Title: Re: serialize collectionBase
Post by: Draftek on November 28, 2007, 04:08:35 PM
The code is merely thrown together for proto-typing at this point.

The parent object in the collection is used to set the parent of each member. I've used this method before and it works really well where you need to 'chain' children.. Think of browser nodes in a treeview control.

If somebody will throw me a 'generics' example, I'd be very interested to see it.

Thanks
Title: Re: serialize collectionBase
Post by: Glenn R on November 28, 2007, 06:14:19 PM
Give this (http://www.theswamp.org/lilly_pond/GlennR/DraftekSerialization101.htm) a run around the yard.

Cheers,
Glenn.
Title: Re: serialize collectionBase
Post by: Glenn R on November 28, 2007, 06:16:49 PM
Whoops! Forgot the starter XML file:

Code: [Select]
<Projects>
  <Project>
    <Number>100</Number>
    <Description>First project</Description>
  </Project>
  <Project>
    <Number>101</Number>
    <Description>Second project</Description>
  </Project>
</Projects>

Place in the same folder as the dll.
Title: Re: serialize collectionBase
Post by: Draftek on November 28, 2007, 06:37:50 PM
I'll give it a shot Glenn.

Thanks
Title: Re: serialize collectionBase
Post by: Draftek on November 28, 2007, 07:40:04 PM
works great! I changed cLites to this:
Code: [Select]
[Serializable]
    public class cLites :List<cLite>
    {

        // constructor - when the collection is created, you need a parent lite
        // to add to all of the children created from the add method

        public cLites(cLite parent)
        {
            m_parentLite = parent;
        }
        #region private members
        // parent lite
        private cLite m_parentLite;

        #endregion

        #region public Members
        [XmlElementAttribute("parentLite", typeof(cLite))]
        public cLite ParentLite
        {
            get { return m_parentLite; }
            set { m_parentLite = value; }
        }

        #endregion

    }

works AND cut out the implementation code AND the wrapper class - Nice!

Looks like I have some reading to do...
Thanks Glenn
Title: Re: serialize collectionBase
Post by: Glenn R on November 28, 2007, 07:45:01 PM
nurries.
Title: Re: serialize collectionBase
Post by: Draftek on November 28, 2007, 07:48:29 PM
okay, you got me with that one. I can usually decipher the Australian but..... :)
Title: Re: serialize collectionBase
Post by: Kerry on November 28, 2007, 07:49:56 PM
yes, generics ..
thats what I meant by the reference to the last paragraph of the article I referenced to.


Glenn,
those samples look functionally familiar.


Title: Re: serialize collectionBase
Post by: Kerry on November 28, 2007, 07:51:41 PM
no flaming worries = nurries.

or

all is cool.

added:
it's actually just 'no worries'
Strine is easy if you hold your nose and run words together.

also added later:
* sometimes reality should not stand in the way of a good story

Title: Re: serialize collectionBase
Post by: MaksimS on November 29, 2007, 04:13:05 AM
IMHO, everything's fine unless it's a keyed collection of elements. Here's an example:

1) There's an Attribute type, having Name property (String). Two Attributes are considered equal if their Names are equal.
2) There's also a generic keyed collection of Attribute elements named Attributes:

Code: [Select]
<Serializable()> _
Public Class Attributes
    Inherits KeyedCollection(Of String, Attribute)

    Sub New()
        MyBase.New()
    End Sub

    Protected Overrides Function GetKeyForItem(ByVal item As Attribute) As String
        Return item.Name
    End Function

    ...

Then, here's how you access collection elements (by name):

Code: [Select]
Dim myAttributes As New Attributes()
... fill the collection ...
Dim myAttribute As Attribute = myAttributes("KeyName")

Both Attribute and Attributes types need to be decorated with Serializable() attribute. That's it. You don't need to bother with property/method serialization attributes since only Public ones will get serialized/deserialized.

Regards,
Maksim Sestic

Title: Re: serialize collectionBase
Post by: Glenn R on November 29, 2007, 04:41:07 AM
Glenn,
those samples look functionally familiar.

Hehe...I thought you would spot that Kerry.
Title: Re: serialize collectionBase
Post by: Glenn R on November 29, 2007, 04:42:39 AM
it's actually just 'no worries'

also added later:
* sometimes reality should not stand in the way of a good story


Correct on both counts there Kerry and yes you definately shouldn't let reality ruin a good yarn.