【问题标题】:Why doesn't my clone code compile?为什么我的克隆代码无法编译?
【发布时间】:2013-06-10 00:12:38
【问题描述】:

我想使用这个简单的克隆界面。看起来它应该编译,但它没有。我收到一条消息说我的BObject 类没有实现DeepClone()。我不明白这一点,因为我有一个DeepClone() 方法和我的BObject实现 IObject

interface IDeepCloneable<T>
{
    T DeepClone();
}

interface IObject : IDeepCloneable<IObject>
{
    string Name { get; }
    double Sales { get; }
}

//'BObject' does not implement interface member
//  'IDeepCloneable<IObject>.DeepClone()'
class BObject : IObject
{
    public string Name { get; set; }
    public double Sales { get; set; }

    public BObject DeepClone()
    {
        return new BObject() { Name = this.Name, Sales = this.Sales };
    }
}

我是否声明我的接口错误?


或者可能是DeepClone 实现?我可以使用这段代码:

public IObject DeepClone() //returns an IObject instead of a BObject
{
    return new BObject() { Name = this.Name, Sales = this.Sales };
}

我遇到的问题是没有检查 BObject.DeepClone() 方法是否返回 BObject 作为结果。我可以有一个看起来像这样的类:

class BObjectImposter : IObject
{
    public string Name { get; set; }
    public double Sales { get; set; }

    public IObject DeepClone()
    {
        //returns a BObject instead of a BObjectImposter
        return new BObject() { Name = this.Name, Sales = this.Sales };
    }
}

使用这个类,我可以这样写:

BObjectImposter objImp = new BObjectImposter();
IObject copy = objImp.DeepClone();

我可能认为copyBObjectImposter 的实现,但它实际上是一个不相关的类BObject 的实现,它恰好也实现了IObject。我知道接口的意义在于我使用哪种实现并不重要,但这对我来说似乎不是好的代码。也许在我的BObjectImposter 实现中的某个地方,我希望DeepClone() 返回一个BObjectImposter 对象。此外,IObject 的一种实现不应依赖于 IObject 的另一种实现。


也许我可以让IObject 成为一个抽象类并在那里声明DeepClone()。如果我有一个实现(称为ObjectA),我需要在构造函数中设置Sales 之前设置Name,以及我需要的另一个实现(称为ObjectB),这似乎可能会破坏我的设计在构造函数中设置Name之前设置Sales

【问题讨论】:

    标签: c# interface clone


    【解决方案1】:

    正如您在问题中所暗示的那样,IObject 实现了 IDeepClonableIObject>,因此其 DeepClone() 方法必须返回 IObject

    你需要一路使用CRTP

    interface IObject<T> : IDeepCloneable<T> where T : IObject<T>
    class BObject : IObject<BObject>
    

    (您还应该将where T : IDeepCloneable&lt;T&gt; 添加到IDeepCloneable

    【讨论】:

    • 有了你的代码,我该如何使用界面?例如,这一行给出了一个错误:IObject a = new BObject();IObject requires 1 type argument
    • @user2023861:每个使用IObject 的方法都必须是通用的。存在这个非常烦人的限制是因为 C# 不支持更高种类的类型。你可以让IObjectT 中协变,这样你就可以一直使用IObject&lt;IObject&gt;
    【解决方案2】:

    因为 IObject 继承了IDeepCloneable&lt;IObject&gt;,所以DeepClone 将返回一个IObject。以下应该有效:

        interface IDeepCloneable<T>
    {
        T DeepClone();
    }
    
    interface IObject<T> : IDeepCloneable<T>
    {
        string Name { get; }
        double Sales { get; }
    }
    
    //'BObject' does not implement interface member
    //  'IDeepCloneable<IObject>.DeepClone()'
    class BObject : IObject<BObject>
    {
        public string Name { get; set; }
        public double Sales { get; set; }
    
        public BObject DeepClone()
        {
            return new BObject() { Name = this.Name, Sales = this.Sales };
        }
    }
    

    【讨论】:

    • 如何使用这些接口?这段代码IObject a = new BObject(); 给了我一个错误,上面写着IObject requires 1 type argument。我可以使用IObject&lt;BObject&gt; a = new BObject();,但这似乎打破了使用接口的想法。
    • 恐怕这就是静态类型的问题。您必须将返回类型参数传递给您的调用类/方法。这是微软从未将 ICloneable 更新为通用的主要原因(我认为)。
    猜你喜欢
    • 1970-01-01
    • 2014-10-03
    • 1970-01-01
    • 2021-06-11
    • 2016-01-08
    • 1970-01-01
    • 2023-03-29
    • 1970-01-01
    相关资源
    最近更新 更多