Saturday, February 19, 2011

Shallow Copy From Inherited Classes

Ok so I have an abstract base class called Product, a KitItem class that inherits Product and a PackageKitItem class that inherits KitItem. ie.

Product
KitItem : Product
PackageKitItem : KitItem

I have my KitItems loaded and I need to load up a collection of PackageKitItems which are, effectively, shallow copies of KitItems.

Currently we are doing what feels to me a hacky shallow copy in the Product constructor like so:

public Product(Product product)
        {
            FieldInfo[] fields = product.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);

            // copy each value over to 'this'
            foreach (FieldInfo fi in fields)
                fi.SetValue(this, fi.GetValue(product));
        }

I've tried setting up a copy on KitItem like so:

public KitItem ShallowCopy()
        {
            return (KitItem)this.MemberwiseClone();
        }

and calling it thus:

PackageKitItem tempPackKitItem = (PackageKitItem)packKitItem.ShallowCopy();

but I get an invalid cast. I'm looking for ideas for the best way to accomplish this.

From stackoverflow
  • In your Product constructor you are already doing some form of shallow copy, aren't you? If you haven't overwritten your constructor, then you should be able to just create a new PackageKitItem that receives a KitItem as its parameter.

    PackageKitItem tempPackKitItem = new tempPackKitItem(kitItem);
    

    Maybe I just misunderstood your question.

  • Strangely I didn't get an error doing this on Visual Studio 2008. I am posting the code so you can see what I am missing or what I am assuming wrong. My guess is that the problem is in one of the class members that you didn't post.

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    using System.Reflection;
    
    namespace WindowsFormsApplication1
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }
    
            private void button1_Click(object sender, EventArgs e)
            {
                PackageKitItem PKI = new PackageKitItem();
                PKI.ID      = 1;
                PKI.KitName = "2";
                PKI.Name    = "3";
                PKI.Package = 4;
    
                PackageKitItem tempPackKitItem = (PackageKitItem)PKI.ShallowCopy();
    
            }
        }
    
    }
    
    public class Product
    {
        public int ID;
        public string Name;
    
        public Product()
        {
        }
    
        public Product(Product product)
        {
            FieldInfo[] fields = product.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
    
            // copy each value over to 'this'
            foreach (FieldInfo fi in fields)
                fi.SetValue(this, fi.GetValue(product));
        }
    
    
    }
    
    public class KitItem:Product
    {
        public string KitName;
        public KitItem ShallowCopy()
        {
            return (KitItem)this.MemberwiseClone();
        }
    
    }
    
    public class PackageKitItem : KitItem
    {
        public int Package;
    
    }
    
  • The problem you have is that since ShallowCopy() is a member of KitItem, MemberwiseClone() is just copying the KitItem fields and returning a KitItem even if the original object is a PackageKitItem.

    I think what you have to do in this circumstance add to KitItem:

    public virtual KitItem ShallowCopy()        
    {            
      return (KitItem) this.MemberwiseClone();        
    }
    

    and in PackageKitItem:

    public override KitItem ShallowCopy()        
    {            
        return (PackageKitItem) this.MemberwiseClone();        
    }
    

    Thus you will get the proper MemberwiseClone() call done depending on the object you are trying to ShallowCopy().

    If you wanted to go further, you could define a ShallowCopy() in Product (returning a Product) and then have overridden versions in KitItem and PackageKitItem each returning their respective shallow copy.

0 comments:

Post a Comment