<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                # 原則32:避免 ICloneable **By D.S.Qiu** **尊重他人的勞動,支持原創,轉載請注明出處:[http://dsqiu.iteye.com](http://dsqiu.iteye.com)** IConeable 聽起來是一個很不錯的想法:你類型實現了 IConeable 接口然后就支持復制。如果你不想要支持復制,你就不需要實現它。但是你的類型不能在真空中存在。你支持 IConeable 的決定會影響它的子類。一旦一個類型支持 ICloneable ,它的所有子類也都必須支持 ICloneable 。它的所有成員的類型都必須支持 ICloneable 或者有其他機制去復制。最后,如果支持深度復制并且當你類型包含 web 對象就會很有問題。 ICloneable 的官方定義就給出了這個問題:它支持深復雜或淺復制。淺復制創建一個新對象包含所有成員變量的復制。如果這些成員變量是引用類型的,新對象引用和原來對象是同一個對象。深復制創建新對象同樣包含所有成員變量的復制。所有的引用類型都會被嵌套復制。對于內置變量,例如整數,深復制和淺復制產生的結果是一樣的。類型支持哪一個?這就依賴于具體的類型。但是在同一個對象混合深復制和淺復制會引起相當不一致的表現。當你去趟了 ICloneable 的渾水,這就再說難免了。大多數情況下,避免使用 ICloneable 使得類更簡單。它很容易使用,并且很容易實現。 任何只包含內置類的成員變量的值類型不需要支持 ICloneable ;簡單的賦值復制 struct 的所有值比 Clone() 更高效。Clone() 會對返回值進行封箱,以至于強制轉換為 System.Object 的引用。調用者必須進行強制類型轉換才能從箱中提取值。這樣做已經夠了。不要重寫 Clone() 函數來進行賦值復制。 如果值類型包含引用類型會怎么樣?最常見的例子是值類型包含一個 string : ``` public struct ErrorMessage { private int errCode; private int details; private string msg; // details elided } ``` string 是一個特殊例子因為它是不可變的類。如果你賦值一個 ErrorMessage 對象,兩個 ErrorMessage 對象會引用相同一個字符串。它不會引起一般引用類型的可能會出現的錯誤。如果你通過任何一個引用改變 msg 變量,會創建一個 string 對象(查看原則16)。 普遍的例子是創建一個包含任意引用變量的 struct 會更復雜。這也很少見。struct 內置的賦值創建淺復制,兩個 struct 會引用相同的對象。為了創建深復制,你需要克隆包含的引用類型對象,而且你需要知道這個引用類型通過 Clone() 方法來支持深復制。這樣,要做的工作如果包含的引用類型支持 ICloneable ,并且它的 Clone() 方法創建深復制。 下面我們開始討論引用類型。引用類型支持 ICloneable 接口說明它們支持淺復制或深復制。你應該謹慎支持 ICloneable 因為這樣就必須讓這個類的所有子類也支持 ICloneable 。考慮下面的簡單的繼承結構: ``` class BaseType : ICloneable { private string label = "class name"; private int[] values = new int[10]; public object Clone() { BaseType rVal = new BaseType(); rVal.label = label; for (int i = 0; i < values.Length; i++) rVal.values[i] = values[i]; return rVal; } } class Derived : BaseType { private double[] dValues = new double[10]; static void Main(string[] args) { Derived d = new Derived(); Derived d2 = d.Clone() as Derived; if (d2 == null) Console.WriteLine("null"); } } ``` 如果你運行這個程序,你會發現 d2 的值是 null 。Derived 類從基類 BaseType 繼承 ICloneable.Clone() ,但是實現卻對子類是不正確的:它只是克隆基類 BaseType.Clone() 創建基類對象,而不是子類對象。這就是測試程序中為什么 d2 為 null —— 它不是 Derived 對象。然而,即使你克服了這個問題, BaseType.Clone() 不能復制定義在 Derived 的 dValues 數組。所以當你實現 ICloneable ,你必須強制所有子類也都實現。實際上,你可以提供一個鉤子函數讓所有子類能有自己的實現(查看原則23)。為了支持克隆,子類只能添加實現了 ICloneable 的值類型或引用類型的成員變量。這是對于子類是非常嚴格的限制。在基類支持 ICloneable 增加了子類的負擔,所以你應該在非封閉的類避免實現 ICloneable 。 如果整個類的繼承結構都必須實現 ICloneable ,你可以差un感覺一個 abstract Clone() 方法,強制子類實現它。在這些例子,你還需要定義子類復制基類成員的方法。可以定義一個 protected 的復制構造函數: ``` class BaseType { private string label; private int[] values; protected BaseType() { label = "class name"; values = new int[10]; } // Used by devived values to clone protected BaseType(BaseType right) { label = right.label; values = right.values.Clone() as int[]; } } sealed class Derived : BaseType, ICloneable { private double[] dValues = new double[10]; public Derived() { dValues = new double[10]; } // Construct a copy // using the base class copy ctor private Derived(Derived right) : base(right) { dValues = right.dValues.Clone() as double[]; } public object Clone() { Derived rVal = new Derived(this); return rVal; } } ``` 基類沒有實現 ICloneable ;提供了 protected 的復制構造函數,讓子類能拿復制基類的部分。葉節點的類都是封閉的,當有必要的時候實現 ICloneable 。基類不會強制所有子類實現 ICloneable ,但是必須提供子類因支持 ICloneable 而需要的方法。 ICloneable 仍有它的用處,但是這是一個例外而不是指導規則。 .NET 框架更新支持泛型時,而沒有添加 ICloneable&lt;T&gt; 的支持是非常有意義的。你不應該對值類型添加 ICloneable 的支持;而是使用賦值操作。當復制操作對葉借點封閉類很重要,你就應該添加 ICloneable 支持。當基類支持 ICloneable 你就為此創建 protected 復制夠函數。對于其他的所有情況,避免使用 ICloneable 。 小結: 這個原則其實強調的重點是不管是值類型還是引用類型如果實現了 ICloneable 接口,這個類的成員變量和繼承結構也要實現 ICloneable ,才能做到深復制和淺復制的一致性。這點其實跟 Java 是一樣的! 歡迎各種不爽,各種噴,寫這個純屬個人愛好,秉持”分享“之德! 有關本書的其他章節翻譯請[點擊查看](/category/297763),轉載請注明出處,尊重原創! 如果您對D.S.Qiu有任何建議或意見可以在文章后面評論,或者發郵件(gd.s.qiu@gmail.com)交流,您的鼓勵和支持是我前進的動力,希望能有更多更好的分享。 轉載請在**文首**注明出處:[http://dsqiu.iteye.com/blog/2087490](/blog/2087490) 更多精彩請關注D.S.Qiu的博客和微博(ID:靜水逐風)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看