在C#中克隆一个对象

4

我想使用 ICloneable 接口克隆一个对象,但由于某些原因,我的程序无法进行克隆。以下是我的代码:

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;
    }

当我在另一个类中尝试使用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()));
        });
    }

附注:您可能考虑使GeoInfos成为不可变的,这样克隆就变得不必要了。但是当然我不知道在那种特定情况下是否可能或明智。 - CodesInChaos
5个回答

5
您的强制类型转换括号不正确。应该这样写:
GeoInfos.Add((GeoInfo)((ICloneable)item).Clone());

(顺便问一下:为什么要用 .ForEach() ?)
this.GeoInfos = oldGeoInfos.Select(item => ((GeoInfo)((ICloneable)item.Clone()))).ToList();

(同样也能胜任这份工作。)

3
正如其他人所说,您已经明确地实现了接口。我所做的是创建另一个方法,返回克隆方法的类型安全版本,因此我倾向于包括它。
public GeoInfo Clone()
{
    return new GeoInfo(InfoID, InfoName, InfoLocation, Description, InfoType);
}

并将显式实现的克隆方法更改为(应删除public修饰符)...

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

这样你就不必从对象转换为实际类型。
然而,ICloneable存在一些困难:
  • 你不知道克隆是否应该是深层克隆或浅层克隆(译注:即复制对象时是否需要同时复制其引用类型成员)
  • 你必须提供一个允许派生类自我克隆的机制,可以通过虚方法尝试实现。在某些情况下,如果无法确保派生类型中的适当克隆,则我会将我的类密封起来,但这是基于你的架构和需求做出的决策。

1

你应该只调用你的方法

public object Clone()

编辑:
或者调用你的方法

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

注意不要多加()


0

这行代码必须被读取

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

但是,在你的GeoInfo类中,请勿使用显式接口实现(无论如何,你的示例都不应编译),以便阅读:
public object Clone()
{
    //...
}

然后你可以简单地执行

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

0

您已经显式实现了 ICloneable.Clone,这要求在调用该方法之前必须将对象强制转换为 ICloneable

请参阅 MSDN 上的 显式接口实现

如果您希望该方法可在您的对象上调用,请将方法声明更改为:

public object Clone()

或者,如果您想保持静态类型检查,请将当前实现保持不变,并添加以下内容:

public GeoInfo Clone()
{
    return ((ICloneable)this).Clone();
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接