Boxing & Unboxing

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • Airslash
    New Member
    • Nov 2007
    • 221

    #1

    Boxing & Unboxing

    Hello,

    I'm still working on my self-aware classes for database communication, and I have an issue that I'd like to see clarified.

    i've been reading some more about the C# programming, and came across the stuff regarding "boxing and unboxing" of variables. And if I understand that concept correctly, I think it applies to the following situation:

    I have a class called Cell. It holds a string for the columnname and 2 objects for the value and the old_value.
    I'm sure that if I obtain and store the data each time in these objects, I'm bound to disaster performance wise with the boxing & unboxing concept.
    Is there a solution that allows me to store any kind of data in a variable without having to go around the boxing & unboxing stuff?
  • Airslash
    New Member
    • Nov 2007
    • 221

    #2
    I've worked around the problem by using Generics, but I think i've run into another problem now :)

    Consider my class Cell :

    Code:
       public class Cell<T> : ICloneable, IComparable, ISerializable, IXmlSerializable
        {
            #region Constructors
    
            /// <summary>
            /// Creates a new instance of the Cell class without setting
            /// a name of value.
            /// </summary>
            public Cell()
                : this(String.Empty, default(T))
            { }
    
            /// <summary>
            /// Creates a new instance of the Cell class with the specified
            /// name. The value will be set to null.
            /// </summary>
            /// <param name="name"></param>
            public Cell(string name)
                : this(name, default(T))
            { }
    
            /// <summary>
            /// Creates a new instance of the Cell class with the specified name
            /// and value.
            /// </summary>
            /// <param name="name">The name of the Cell.</param>
            /// <param name="value">The raw value of the Cell.</param>
            public Cell(string name, T value)
            {
                this.Name = name;
                this.Value = value;
                this.OldValue = default(T);
            }
    
            /// <summary>
            /// Creates a new instance of the Cell class with the information
            /// passed from the serialization context.
            /// </summary>
            /// <param name="info"></param>
            /// <param name="contect"></param>
            public Cell(SerializationInfo info, StreamingContext contect)
            {
                this.Name = info.GetString("Cell_Name");
                this.Value = (T)info.GetValue("Cell_Value", typeof(T));
                this.OldValue = (T)info.GetValue("Cell_OldValue", typeof(T));
            }
    
            #endregion
    
            #region Properties
    
            /// <summary>
            /// Gets or sets the name of the Cell.
            /// </summary>
            public string Name
            {
                get { lock (this) { return m_name; } }
                set { lock (this) { m_name = value; } }
            }
    
            /// <summary>
            /// Gets or sets the raw value of the Cell.
            /// </summary>
            public T Value
            {
                get { lock (this) { return m_value; } }
                set { lock (this) { this.OldValue = m_value; m_value = value; } }
            }
    
            /// <summary>
            /// Gets whether the contents of this Cell have been modified since
            /// it's creation.
            /// </summary>
            public bool Modified
            {
                get { lock (this) { return EqualityComparer<T>.Default.Equals(m_old_value); } }
            }
    
            /// <summary>
            /// Gets or sets the old value of the Cell.
            /// This function supports the NexusLink framework and should not be used/visible in your code.
            /// </summary>
            internal T OldValue
            {
                get { lock (this) { return m_old_value; } }
                set { lock (this) { m_old_value = value; } }
            }
    
            #endregion
    
            #region Private Fields
    
            private string m_name;      // The name of the Cell.
            private T m_value;          // The raw value of the Cell.
            private T m_old_value;      // The raw old value of the Cell.
    
            #endregion
    
            #region ICloneable Members
    
            /// <summary>
            /// Creates a deep copy of the current Cell by copying over
            /// all the internal datamembers in a bit-wise fashion.
            /// </summary>
            /// <returns>A Clone of the current Cell with the exact same data.</returns>
            public object Clone()
            {
                // Surround the function call with a lock so our datamembers cannot
                // be changed by another thread during the copy process.
                lock (this)
                {
                    // To perform the deep clone operation we need a memorystream
                    // and a formatter.
                    MemoryStream sm = new MemoryStream();
                    IFormatter bf = new BinaryFormatter();
    
                    // Serialize our object into memory.
                    bf.Serialize(sm, this);
    
                    // Position the cursor in the memorystream at the beginning.
                    sm.Seek(0, SeekOrigin.Begin);
    
                    // Deserialize our object into something new.
                    Cell<T> copy = (Cell<T>)bf.Deserialize(sm);
    
                    // Release the memory.
                    sm.Close();
    
                    // Return the copy.
                    return copy;
                }
            }
    
            #endregion
    
            #region IComparable Members
    
            /// <summary>
            /// Compares two Cells against each other based upon their name.
            /// </summary>
            /// <param name="obj">The object to compare against.</param>
            /// <returns>Less then zero if the name is less then the passed Cell's name; zero if both names are equal; Greather then zero if the name if more then the passed Cell's name.</returns>
            /// <exception cref="ArgumentException">The object 'obj' is not of type Cell.</exception>
            public int CompareTo(object obj)
            {
                // Surround the function call with a lock so our data
                // does not get altered by another thread during the call.
                lock (this)
                {
                    // Convert the passed object to type Cell.
                    Cell<T> temp = obj as Cell<T>;
    
                    // First check if the passed object is of the same type.
                    if (temp == null)
                    {
                        throw new ArgumentException("The passed object 'obj' is not of type Cell");
                    }
    
                    // Cells are considered identical if there names match. Otherwise they
                    // will be sorted in order of their name.
                    return this.Name.CompareTo(temp.Name);
                }
            }
    
            #endregion
    
            #region ISerializable Members
    
            /// <summary>
            /// Allows the object to be serialized for transport or storage. This function stores
            /// all the required information from the object into the SerializationInfo object.
            /// The StreamingContext provides additional information about the destination of
            /// the serialization.
            /// </summary>
            /// <param name="info">The SerializationInfo object to hold the data.</param>
            /// <param name="context">Additional information about the destination of the serialization.</param>
            public void GetObjectData(SerializationInfo info, StreamingContext context)
            {
                // Surround our call with a lock, because we don't want our
                // data changed during the retrieval process.
                lock (this)
                {
                    // Add our data to the SerializationInfo object.
                    info.AddValue("Cell_Name", this.Name);
                    info.AddValue("Cell_Value", this.Value);
                    info.AddValue("Cell_OldValue", this.OldValue);
                }
            }
    
            #endregion
    
            #region IXmlSerializable Members
    
            /// <summary>
            /// Only used by the DataSet in .NET, therefor this function always
            /// returns null because we're not a DataSet.
            /// </summary>
            /// <returns>null</returns>
            public System.Xml.Schema.XmlSchema GetSchema()
            {
                return null;
            }
    
            /// <summary>
            /// This function will read out the XML and rebuild the entire Cell object
            /// based upon the information stored in the XML.
            /// </summary>
            /// <param name="reader">The XmlReader to parse the XML document.</param>
            public void ReadXml(System.Xml.XmlReader reader)
            {
                // Consume the root element first of the XML file.
                reader.ReadStartElement();
    
                // Read the first attribute of the root element, this should be the name
                // of our Cell.
                this.Name = reader.GetAttribute("name");
    
                // Read the value of our cell next.
                reader.ReadStartElement("value");
                this.Value = (T)reader.ReadContentAs(typeof(T), null);
                reader.ReadEndElement();
    
                // Read the old value of cell.
                reader.ReadStartElement("oldvalue");
                this.OldValue = (T)reader.ReadContentAs(typeof(T), null);
                reader.ReadEndElement();
    
                // Consume the root end tag.
                reader.ReadEndElement();
            }
    
            /// <summary>
            /// This function will write out the attributes of our class
            /// into the XML file. Because we wish that a Cell is represented
            /// as a single element, we will add the values as attributes.
            /// </summary>
            /// <param name="writer">The XmlWriter to write the XML file.</param>
            public void WriteXml(System.Xml.XmlWriter writer)
            {
                // Write the name of our cell as an attribute in the root tag.
                // We always assume the root tag to be present.
                writer.WriteAttributeString("name", this.Name);
    
                // Now we will write the elements to contain the values of our Cell.
                // These will be childnodes of the Cell element.
                writer.WriteStartElement("value");
                writer.WriteValue(this.Value);
                writer.WriteEndElement();
    
                // As last step we write the "old value" of the Cell element.
                // Just like the "value" it's a child of Cell.
                writer.WriteStartElement("oldvalue");
                writer.WriteValue(this.OldValue);
                writer.WriteEndElement();
    
                // We never write the root elements.
            }
    
            #endregion
        }

    Now I have a class Row, that holds a generic list of type Cell<T>, but I'm confused on how to properly work with or define the type T for Cell in my row.

    Code:
        class Row : ICloneable, ISerializable, IXmlSerializable
        {
            public Row()
            { }
    
            internal Row(List<Cell<Type>> cells)
            { }
    
            public bool Add(Cell<Type> cell)
            { }
    
            public bool Remove(Cell<Type> cell)
            { }
    
            public bool Contains(Cell<Type> cell)
            { }
    
            internal bool ContainsModifiedCells()
            { }
    
            public Cell<Type> this[int index]
            { 
                get{}
            }
    
            public Cell<Type> this[string name]
            {
                get{}
            }
    
            public int Count
            {
                get { lock (this) { return m_cells.Count; } }
            }
    
            private List<Cell<Type>> m_cells;
    Is this correct? The compiler is not complaining, but it looks so odd and confusing....

    Comment

    • Plater
      Recognized Expert Expert
      • Apr 2007
      • 7872

      #3
      You are changing <Type> to the type you want right?
      private List<Cell<Type> > m_cells;

      Comment

      • Airslash
        New Member
        • Nov 2007
        • 221

        #4
        So using the "Type" class from reflection instead of just "T" will work?

        The idea is to have a list of Cell<T> objects. Each Cell in the list should be able to have a different type at runtime. That's what I'm trying to achieve. I don't want to make my Row class Generic or type bound either, I just want to be able to do this for example:

        Code:
        Row r = new Row'();
        r.AddCell(new Cell<int>("ID"));
        r.AddCell(new Cell<string>("Name"));
        r.AddCell(new Cell<object>("Image"));
        r.AddCell(new Cell<int>("Amount"));
        r.Commit();
        That's what I'm trying to achieve, so I can reuse the single Cell class without having to worry about bocxing.unboxin g values when retrieving info from the database. Hope I made it clear what I'm trying to achieve.

        Comment

        • Plater
          Recognized Expert Expert
          • Apr 2007
          • 7872

          #5
          Yeah I can see what you want, but List<Cell<Type> > will force your Cell objects to contain the Type class (or derived classes) and not Type T.

          At some point I think you are going to have to box/unbox your entries if you want a collection with different types in it.

          Comment

          • Airslash
            New Member
            • Nov 2007
            • 221

            #6
            any way around the issue then?

            I tried defining them it as
            Code:
            List<Cell<T>> m_cells;
            But this gives me compiler errors, saying something about namespace T not recognised.
            Surely there must be a way to implement this without making my Row class Generic, or type bound?

            Comment

            • Plater
              Recognized Expert Expert
              • Apr 2007
              • 7872

              #7
              If it were possible, I would think there would already be a class that does it?
              You've pretty much just re-created the DataRow object right now

              Comment

              Working...