Question

I want to clone an object with using the ICloneable interface and for some reason I can't clone in my program. Here is my code:

public class GeoInfo : ICloneable
{
    private long InfoID;
    private string InfoName;
    private Location InfoLocation;
    private string Description;
    private InfoTypes InfoType;
    public GeoInfo(long InfoID)
    {

        this.InfoID = InfoID;
    }
    public GeoInfo(long InfoID, Location InfoLocation):this(InfoID)
    {
        this.InfoLocation = InfoLocation;
    }
    public GeoInfo(long InfoID, string InfoName, Location InfoLocation, string Description, InfoTypes InfoType):this(InfoID,InfoLocation)
    {
        this.InfoName = InfoName;
        this.Description = Description;
        this.InfoType = InfoType;
    }
    public object ICloneable.Clone()
    {
        GeoInfo toReturn = new GeoInfo(InfoID, InfoName, InfoLocation, Description, InfoType);
        return (object)toReturn;
    }

}

Inside another class when I am trying to use the Clone() method, for some reason the compiler can't find the method. Here is my other method that is trying to Clone:

public InfoLayer(string LayerName,List<GeoInfo> oldGeoInfos)
    {
        this.LayerName = LayerName;
        this.GeoInfos = new List<GeoInfo>();
        oldGeoInfos.ForEach((item) =>
        {
            GeoInfos.Add((GeoInfo)((ICloneable)item.Clone()));
        });
    }
Was it helpful?

Solution

The parentheses around your cast are not correct. It should read

GeoInfos.Add((GeoInfo)((ICloneable)item).Clone());

(By the way: Why the .ForEach() ?

this.GeoInfos = oldGeoInfos.Select(item => ((GeoInfo)((ICloneable)item.Clone()))).ToList();

does the job as well.)

OTHER TIPS

As others have said you have implemented the interface explicitly.What I do is create another method that returns a typesafe version of the clone method so I tend to include.

public GeoInfo Clone()
{
    return new GeoInfo(InfoID, InfoName, InfoLocation, Description, InfoType);
}

and change the explicity implemented clone method to be (the public modifier should be removed)...

object ICloneable.Clone()
{
    return Clone();  //will call the public method as above
}

This way you don't have to cast from an object to the real type.

However there are a number of difficulties with ICloneable:

  • You don't know if the clone should be a deep or shallow clone
  • You have to provide a mechanism for derived classes to clone itself which you can attempt to do via virtual methods. I tend to seal my classes in cases I cannot ensure proper cloning in derived types but that is a decision to be made based around your architcture and needs.

You should only call your method

public object Clone()

Edit:
Or call your method

oldGeoInfos.ForEach((item) =>
{
    GeoInfos.Add((GeoInfo)(((ICloneable)item).Clone()));
});

note extra ().

The line must read

GeoInfos.Add((GeoInfo)((ICloneable)item).Clone());

But consider in your GeoInfo class to not use explicit interface implementation (your example shouldn't compile anyway), so that it reads:

public object Clone()
{
    //...
}

Then you can simply do

GeoInfos.Add((GeoInfo)item.Clone());

You have implemented ICloneable.Clone explicitly, which requires that the object is cast to ICloneable before the method cane be called.

See Explicit Interface Implementation on MSDN.

If you want the method callable on your object, change the method declaration to:

public object Clone()

Alternatively, if you want to keep static type checking, leave your current implementation as-is, and add the following:

public GeoInfo Clone()
{
    return ((ICloneable)this).Clone();
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top