2009-03-10 26 views
5

Tôi đã tạo một lớp có tên là Màu sắc. Tôi đang thiết lập các thuộc tính nhất định trên đối tượng Colors và thiết lập nó trong một biến Session. Khi tôi truy cập vào biến Session trên một trang khác, tôi nhận thấy rằng nếu tôi thay đổi các thuộc tính trên objColors bên dưới, nó sẽ thay đổi Session và không giữ lại các thuộc tính ban đầu đó là những gì tôi muốn nó làm. Dưới đây là ví dụ:Làm cách nào để tạo bản sao của một đối tượng?

Session["Colors"] = Colors; 

Colors objColors = Session["Colors"]; 

//If I change objColors, it changes the Session. I don't want this to happen. 

Có cách nào tốt hơn để giữ lại các thuộc tính ban đầu không? tại sao nó làm vậy?

Trả lời

7

Tạo hàm tạo bản sao cho Màu sắc. Sau đó, làm điều này.

Colors objColors = new Colors((Colors)Session["Colors"]); 

Trong công cụ xây dựng mới của bạn, chỉ cần sao chép các giá trị bạn cần và thực hiện các công việc liên quan đến hàm dựng khác của bạn.

Điều đang xảy ra trong mã của bạn là bạn đang nhận được con trỏ cho đối tượng Màu sắc. Phiên ["Màu sắc"] và objColors trỏ đến cùng một đối tượng trong bộ nhớ, vì vậy khi bạn sửa đổi một, các thay đổi được phản ánh trong cả hai. Bạn muốn một đối tượng Màu sắc mới của spankin, với các giá trị được khởi tạo từ objColors hoặc Session ["Colors"].

chỉnh sửa: Một constructor sao chép có thể trông như thế này:

public Colors(Colors otherColors) 
{ 
    this.privateVar1 = otherColors.privateVar1; 
    this.publicVar2 = otherColors.publicVar2; 
    this.Init(); 
} 
+0

Bạn có thể cụ thể hơn về cách tạo hàm tạo bản sao không? – Xaisoft

+0

@Xaisoft đó là công việc của bạn để tạo ra logic để sao chép. Đó là vấn đề lấy từng giá trị trên đối tượng cũ và áp dụng nó cho cái mới. –

3

Bạn có thể thực hiện phương pháp nhân bản của riêng bạn để tạo ra một "bản sao" của một đối tượng. Lý do điều này xảy ra là do việc gán Colors objColors = Session["Colors"]; là một nhiệm vụ tham chiếu, điều này là do thiết kế. Tất cả những gì bạn đang làm là tạo một tham chiếu phạm vi cục bộ cho một đối tượng đã tồn tại. Hãy xem IClonable để nhân bản đối tượng thực tế. Điều này là không cần thiết hoặc bạn có thể thực hiện các phương pháp sao chép của riêng bạn. Bạn cũng có thể muốn xem MemberwiseClone tùy thuộc vào độ sâu của đối tượng.

2

Đối tượng đang được truy cập bằng tham chiếu thay vì theo giá trị. See here. Có một số cách để thay đổi điều này. Kiểm tra trang web để biết thông tin chi tiết.

3

Hãy thử một hàm tạo bản sao.

Ví dụ: link

1

Không có một cách xây dựng và thực hiện theo mặc định, nhưng bạn có thể có được điều này bằng cách thực hiện ICloneable và gọi MemberwiseClone. Điều này sẽ chỉ làm việc cho một bản sao nông - nếu đối tượng của bạn có chứa các đối tượng khác, bạn sẽ cần phải sao chép chúng là tốt. Triển khai đơn giản sẽ là:

public class Bla : ICloneable 
{ 
    string _someFieldToClone; 

    object ICloneable.Clone() 
    { 
     return this.Clone(); 
    } 

    public Bla Clone() 
    { 
     return (Bla)MemberwiseClone(); 
    } 
} 
+0

ICloneable không được chấp nhận? – erikkallen

+0

@erikkallen: Không. http://msdn.microsoft.com/en-us/library/system.icloneable.aspx –

1

Điều này thực hiện vì bạn không thực sự sao chép đối tượng nhưng sao chép tham chiếu đến đối tượng. Bạn có thể làm một bản sao sâu trong C# dễ dàng sử dụng serialization nhị phân:

public static MemoryStream Serialize(object data) 
    { 

     MemoryStream streamMemory = new MemoryStream(); 
     BinaryFormatter formatter = new BinaryFormatter(); 
     formatter.AssemblyFormat = FormatterAssemblyStyle.Simple; 

     formatter.Serialize(streamMemory, data); 

     return streamMemory; 


    } 



    public static Object Deserialize(MemoryStream stream) 
    { 

     BinaryFormatter formatter = new BinaryFormatter(); 
     formatter.AssemblyFormat = FormatterAssemblyStyle.Simple; 
     return formatter.Deserialize(stream); 

    } 

Bạn có thể gọi hai phương pháp này là người đầu tiên đưa một đối tượng và ghi dữ liệu của mình cho một MemoryStream. Sau đó, bạn có thể gọi Deserialize để có được một bản sao mới của một đối tượng dựa trên dữ liệu đó.

Một điều cuối cùng đối tượng của bạn cần được Serializable làm điều này bằng cách đặt thuộc tính Serializable trên mỗi đối tượng.

0

Điều này là do các đối tượng objColors và Session ["Colors"] là cùng một đối tượng.Nếu bạn muốn lưu trữ một bản sao và giữ bản gốc, bạn cần phải làm cho đối tượng của bạn có thể khóa được.

Xem sau SO Q & A cho một con trỏ đi đúng hướng:

Deep cloning objects

2

câu trả lời khác đều đề nghị nhân bản trong cách này hay cách khác. Một giải pháp thay thế có thể có hoặc không phù hợp với tình huống cụ thể của bạn là làm cho loại của bạn không thay đổi được. Các hoạt động mà trước đây đã biến đổi kiểu của bạn bây giờ sẽ trả về một thể hiện mới của kiểu, lấy dữ liệu từ đối tượng ban đầu và thực hiện các thay đổi thích hợp và để nguyên bản gốc nguyên vẹn. Đây là cách tiếp cận mà các lớp học String mất, ví dụ.

Bạn vẫn sẽ phải viết mã thích hợp để sao chép dữ liệu trong một cá thể, tất nhiên - nhưng mã làm việc với loại này cũng có thể sẽ trở nên đơn giản hơn.

Điều này có thể không phù hợp trong trường hợp của bạn, nhưng đó là một kỹ thuật ít nhất phải cân nhắc.

0

Kể từ Colors lớp là một mà bạn đã tạo, và tôi giả sử bạn đang khá mới để phản đối chương trình định hướng, bạn có thể tạo một bản sao construtor như Stuart nói với một cái gì đó tương tự như sau:

public class Colors 
{ 
    public int Property1; 
    public int Property2; 
    public int Property3; 
    public Colors() 
    { 
    //Do your regular constructor here 
    } 
    public Colors(Colors colorToCopy) 
    { 
    this.Property1 = colorToCopy.Property1; 
    this.Property2 = colorToCopy.Property2; 
    this.Property3 = colorToCopy.Property3; 
    } 
} 

Nhân bản thông qua serialization là một giải pháp tổng quát hơn và đảm bảo một bản sao sâu (có nghĩa là nó sẽ sao chép làm cho các bản sao thuộc tính cũng như, cũng như các thuộc tính của thuộc tính) nhưng khó hiểu hơn một chút. Với giải pháp này, nếu các thuộc tính không phải là các kiểu dữ liệu nguyên thủy thì các loại dữ liệu đó sẽ không phải là các bản sao trừ khi bạn tạo các bản sao đó một cách rõ ràng.

0

Khi bạn có một biến và gán giá trị phiên cho nó, bạn sẽ nhận được một con trỏ cho cả hai.

Colors objColors = (Colors)Session["Colors"]; 

Phiên ["Colors"] và objColors trỏ đến cùng một đối tượng trong bộ nhớ, khi bạn thay đổi một, thay đổi được phản ánh trong cả hai.

Nếu bạn muốn độc lập, cần phải nhận được Bản sao sâu đối tượng của bạn. Bạn phải triển khai giao diện IClonable cho Invoice và tất cả các lớp liên quan của nó:

public class Colors: IClonable 
{ 
    public int Red; 
    public int Green; 
    public int Blue; 

    public object Clone() 
    { 
    return this.MemberwiseClone(); 
    } 
} 

Bây giờ bạn có một bản sao sâu thực sự về đối tượng hóa đơn của bạn.

Colors objColors = (Colors)((Colors)Session["Colors"]).Clone(); 

biết thêm thông tin tại địa chỉ: đối tượng nhân bản với IClonableMemberwiseClone tùy thuộc vào đối tượng của bạn đi sâu như thế nào.

Các vấn đề liên quan