结构或深层副本 - C#

mar*_*ked 6 c# mono performance struct

我终于设法复制了我的对象的值类型,一个使用字典来存储动态属性的类.我想知道两件事,单声道兼容性和效率.我是C#的新手,一般都有很多关于编程的知识,所以如果我滥用了几个短语就道歉:P

我用过这个方法你如何在.NET中做一个对象的深层复制(特别是C#)?...复制我的对象 我也会有数百个这样的对象,并且想知道以这种方式复制它们是非常低效的吗?结构会是更好的选择吗?但我不确定何时使用结构.它可以用单声道移植吗?一些谷歌搜索表明这种序列化可能会引发一个问题.

Ada*_*son 3

根据评论中的后续回复,您正在寻找的最佳解决方案是最简单的解决方案:自己编写代码来复制对象。

如果您的类确实像存储自定义属性的键/值对的字典包装器一样简单,则可以使用Dictionary(IDictionary)构造函数将值从一个字典复制到另一个字典。

class MyWrapper
{
    private Dictionary<string, object> properties = 
                                         new Dictionary<string, object>();

    public MyWrapper Clone()
    {
        MyWrapper output = new MyWrapper();

        output.properties = new Dictionary<string, object>(properties);
    }
}
Run Code Online (Sandbox Code Playgroud)

显然,这是一个简化的类,实际上不执行任何操作,但根据您的描述,这应该可以满足您的需要。没有反射,没有“陷阱”,只是从一个字典到另一个字典的值的简单复制。

编辑

我不能谈论单声道可移植性,因为我是一名仅使用 Windows 的开发人员,但就效率而言,复制所需内容的显式解决方案将比基于反射的解决方案轻而易举地获胜。

在基于引用的面向对象语言中,任何任意类型的真正深层复制的概念都不容易(甚至安全)实现。虽然简单的类复制起来很简单,但引用循环、没有无参数构造函数的类以及不可变类型却带来了挑战。

例如,考虑这个类:

public class Foo
{
    public Foo Next { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

这几乎是单链表最简单的实现。简单的深度复制算法将从 的第一个实例开始Foo,然后通过递归地沿着Next引用链向下导航来克隆它,直到遇到一个null值。然而,这样做,我们不仅会耗尽内存,而且最终会得到不代表原始对象的实际克隆的对象:

Foo first = new Foo();

first.Next = new Foo();

first.Next.Next = first;
Run Code Online (Sandbox Code Playgroud)

这是完全合法(甚至合理)的事情,但现在我们有一个循环引用循环,它将破坏我们幼稚的克隆算法。所以现在我们必须实现一个对象缓存。

Dictionary<object, object> clonedObjects;
Run Code Online (Sandbox Code Playgroud)

现在,在克隆算法中,当为属性或字段赋值时,我们检查缓存以查看我们要复制的引用是否已被克隆。如果有,我们将使用该值而不是克隆一个新值。这将为我们提供一个全新的对象图,它代表我们的原始对象,也是一个完整的克隆。太棒了,对吧?

现在,无参数构造函数怎么样?从完全通用的意义上来说,这个问题甚至无法解决。如果我创建这个类:

public class Bar
{
    public Bar(string gotcha) { }
}
Run Code Online (Sandbox Code Playgroud)

没有办法简单地克隆这个类;因为您无法知道如何调用构造函数(您可以ConstructorInfo反射性地获取构造函数,但是如何调用它的语义将完全未知。您可以做的最好的事情就是存储元数据(通过类)关于调用哪个构造函数以及如何调用它(例如,按应传递顺序排列的字段列表),但这需要事先了解克隆机制,并且还意味着构造函数的参数字段在原始对象上,情况不一定如此。

现在我们又遇到了另一个障碍:不可变的引用类型。这也可能导致意外行为。不可变引用类型是其(外部可见)值不能更改的引用类型;在大多数情况下,这些类旨在展示值类型语义。它们还经常缺少无参数构造函数(甚至可能根本没有可公开访问的构造函数),这使它们受到我们之前的刺激,但它们也可能使用基于工厂的方法,以便它们可以确保引用相等也意味着值相等,反之亦然(后一种情况不太常见,但如果我们谈论的是一种完全幼稚的克隆机制的算法,那么我们必须涵盖它)。这又意味着另一个自定义属性,指示克隆机制应该简单地复制引用而不是克隆实际对象。

因此,简而言之,在处理任意类型时,完全简单的深度复制机制根本不可能。类型的设计必须考虑到克隆机制,并且可能必须做出让步或以特定方式装饰自己才能与其一起工作。这与相对不常见的需求相结合,可能就是为什么现在没有框架级深度复制机制,以及为什么您应该考虑更明确的复制机制,在该机制中您知道要复制什么(以及什么可能不重要),以便您可以确定你得到的就是你想要的。