簡體   English   中英

結構或深拷貝 - C#

[英]Struct or Deep copy - C#

我終於設法復制了我的 object 的值類型,一個使用字典存儲動態屬性的 class。 我想知道兩件事,mono 兼容性和效率。 我是 C# 的新手,總體上還有很多關於編程的知識,所以如果我誤用了一些短語,我深表歉意:P

我使用了這種方法你如何在 .NET 中做一個 object 的深拷貝(特別是 C#)? ...復制我的 object。 我也會有數百個這樣的對象,並且想知道以這種方式復制它們效率很低嗎? 結構會是更好的選擇嗎? 但是,我不確定何時使用結構。 它可以與 mono 一起移植嗎? 一些谷歌搜索表明這種序列化可能會引起問題。

根據評論中的后續回復,您正在尋找的最佳解決方案是最簡單的解決方案:編寫代碼以自己復制 object。

如果您的 class 真的像一個存儲自定義屬性的鍵/值對的字典的包裝器一樣簡單,則可以使用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);
    }
}

顯然,這是一個簡化的 class 實際上並沒有任何事情,但是根據您的描述,這應該可以滿足您的需求。 沒有反射,沒有“陷阱”,只是從一個字典到另一個字典的簡單副本。

編輯

我不能談論 mono 的可移植性,因為我是一個純 Windows 開發人員,但至於效率,一個顯式的解決方案,你復制你需要的東西將是一個基於反射的解決方案的輕松贏家。

任何任意類型的真正深拷貝的概念在基於引用的面向對象語言中都不容易(甚至安全地)實現。 雖然簡單的類很容易復制,但引用循環、沒有無參數構造函數的類和不可變類型都存在挑戰。

例如,考慮這個 class:

public class Foo
{
    public Foo Next { get; set; }
}

這幾乎是單鏈表的最簡單實現。 一個簡單的深拷貝算法將從Foo的第一個實例開始,然后通過遞歸地向下導航Next引用鏈來克隆它,直到它遇到null值。 但是,這樣做,我們不僅會吃掉 memory,而且最終會得到不代表原始副本的對象:

Foo first = new Foo();

first.Next = new Foo();

first.Next.Next = first;

這是一件完全合法(甚至是合理)的事情,但現在我們有一個循環引用循環,它將破壞我們幼稚的克隆算法。 所以現在我們必須實現一個 object 緩存。

Dictionary<object, object> clonedObjects;

現在,在克隆算法中,當為屬性或字段賦值時,我們檢查緩存以查看我們要復制的引用是否已經被克隆。 如果有,我們使用該值而不是克隆一個新值。 這將為我們提供一個全新的 object 圖,它代表我們原來的 object,也是一個完整的克隆。 太好了,對吧?

現在,無參數構造函數呢? 這甚至在一個完全一般的意義上都無法解決。 如果我創建這個 class:

public class Bar
{
    public Bar(string gotcha) { }
}

沒有辦法從幼稚的意義上克隆這個 class; 因為您無法知道如何調用構造函數(您可以反射性地獲取ConstructorInfo ,但如何調用它的語義將是完全未知的。您可以做的最好的事情是存儲元數據(通過自定義屬性類)關於調用哪個構造函數以及如何調用它(例如,按照傳遞順序排列的字段列表),但這需要事先了解克隆機制,並且還意味着構造函數的 arguments原始 object 上的字段,不一定是這種情況。

現在我們在混合中加入另一個障礙:不可變引用類型。 這也可能導致意外行為。 不可變引用類型是其(外部可見)值不能改變的引用類型; 在大多數情況下,這些類旨在展示值類型語義。 它們還經常缺少無參數構造函數(甚至可能根本沒有可公開訪問的構造函數),使它們遭受我們之前的煩惱,但它們也可能使用基於工廠的方法,以便它們可以確保引用相等也意味着值相等,反之亦然(后一種情況不太常見,但如果我們談論的是一種完全幼稚的克隆機制的算法,那么我們必須涵蓋它)。 這再次意味着另一個自定義屬性,表明克隆機制應該簡單地復制引用而不是克隆實際的 object。

因此,簡而言之,在處理任意類型時,根本不可能實現完全幼稚的深度復制機制。 類型必須在設計時考慮到克隆機制,並且可能必須做出讓步或以特定方式裝飾自己才能使用它。 這與相對不常見的要求相結合,很可能是為什么現在沒有框架級別的深度復制機制,以及為什么您應該考慮使用更明確的復制機制,在該機制中您知道要復制什么(以及什么可能無關緊要),這樣您就可以確保你得到的就是你想要的。

結構有一些獨特的特性,在使用它們之前應該認真考慮。

  • 它們都是值類型(這將增加傳遞它們的挑戰)
  • 它們都在堆棧而不是堆上占用 memory
  • 他們必須有無參數的構造函數
  • 沒有結構的 inheritance

http://msdn.microsoft.com/en-us/library/aa288471(v=vs.71).aspx

在詢問結構是否適合您的情況之前,請考慮這些要點。

我通常會堅持只為我的 class 編寫一個方法來創建一個深層副本。 您可能會真正喜歡並使用 generics 和反射的組合來編寫一個非常抽象的DeepClone<T>(T object)類型的方法。 或者走簡單的路,只寫一個適合有問題的 class 的裁縫。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM