Tự động tôi chọn giữa cấu trúc và lớp không phải do vấn đề bộ nhớ nhưng do ngữ nghĩa của loại. Một số loại giá trị của tôi có dung lượng bộ nhớ khá lớn, đôi khi quá lớn để sao chép dữ liệu này mọi lúc. Vì vậy, tôi tự hỏi nếu nó là một ý tưởng tốt để vượt qua bất biến giá trị đối tượng luôn luôn bằng cách tham khảo? Vì các đối tượng không thay đổi nên chúng không thể sửa đổi bằng các phương thức chấp nhận chúng bằng tham chiếu. Có các vấn đề khác khi đi qua tham chiếu không?Truyền các loại giá trị bất biến theo tham chiếu theo mặc định
Trả lời
Một số kiểu giá trị của tôi có bộ nhớ khá lớn
Điều đó cho thấy họ không nên loại giá trị, từ một điểm thực hiện xem. Từ "Hướng dẫn thiết kế cho phát triển Class Libraries", phần "Choosing Between Classes And Structures":
Đừng định nghĩa một cấu trúc trừ loại có tất cả các đặc điểm sau:
- Nó logic đại diện cho một giá trị duy nhất, tương tự như nguyên thủy các loại (số nguyên, gấp đôi, vv).
- Đô thị này có kích thước mẫu nhỏ hơn 16 byte.
- Điều này là không thay đổi.
- Nó sẽ không phải được đóng hộp thường xuyên.
Có vẻ như bạn cần phải tạo ra bất biến tham khảo loại để thay thế. Trong nhiều cách họ kết thúc "cảm giác" như đối tượng giá trị anyway (nghĩ dây) nhưng bạn sẽ không cần phải lo lắng về hiệu quả của việc truyền chúng xung quanh.
"Bất Biến" với nhiều loại giá trị là một khái niệm hơi chất lỏng - và chắc chắn nó không có nghĩa là sử dụng ref
là an toàn:
// int is immutable, right?
int x = 5;
Foo(ref x);
Console.WriteLine(x); // Eek, prints 6...
...
void Foo(ref int y)
{
y = 6;
}
Chúng tôi không thay đổi một phần giá trị - chúng tôi đang thay thế toàn bộ giá trị của x
bằng một giá trị hoàn toàn khác.
tính bất biến là hơi dễ dàng hơn để suy nghĩ về khi nói đến tham khảo các loại - mặc dù thậm chí sau đó bạn có thể có một đối tượng mà của riêng mình sẽ không thay đổi, nhưng có thể tham khảo các đối tượng có thể thay đổi ...
"Nó có kích thước cá thể nhỏ hơn 16 byte". Bạn có thực sự viết một 'lớp Vector3d', bởi vì nó có 24 byte? – hansmaad
@hansmaad Nó chỉ là một hướng dẫn. Mỗi trường hợp không thể được bao phủ bởi nó, nhưng họ là những điều/quy tắc để xem xét khi đưa ra quyết định. – vcsjones
@hansmaad: Nếu loại có thể được * truyền theo giá trị * rất nhiều, thì * có *, bạn nên làm như vậy. Nếu kiểu giá trị không được truyền theo giá trị - nếu bạn chỉ tạo một giá trị và sử dụng nó một cách cục bộ mà không cần chuyển nó sang phương thức khác - hãy tiếp tục và làm cho nó lớn nếu bạn muốn. –
Vì vậy, tôi tự hỏi nếu bạn có nên vượt qua các đối tượng giá trị không thay đổi luôn bằng cách tham chiếu không? Vì các đối tượng không thay đổi nên chúng không thể sửa đổi bằng các phương thức chấp nhận chúng bằng tham chiếu. Có các vấn đề khác khi đi qua tham chiếu không?
Không rõ ý bạn là gì. Giả sử rằng bạn có nghĩa là chuyển nó như một tham số ref
hoặc out
, thì phương thức chỉ có thể gán một cá thể mới cho vị trí lưu trữ. Điều này sẽ sửa đổi những gì người gọi thấy vì vị trí lưu trữ trong callee là bí danh cho vị trí lưu trữ được người gọi truyền.
Nếu bạn đang xử lý các vấn đề về bộ nhớ vì sao chép các phiên bản struct
xung quanh, bạn nên cân nhắc tạo một loại tham chiếu không thay đổi, giống như string
.
tôi nghĩ thực sự là ý tưởng tồi là sử dụng cấu trúc khi tất cả mọi thứ bạn làm điểm để sử dụng các lớp
câu trả lời liên quan: https://stackoverflow.com/questions/2440029/is-it-a-bad-practice-to-pass-structs-by-reference
câu trả lời Jon là tất nhiên đúng; Tôi sẽ thêm điều này vào nó: các loại giá trị là đã được chuyển qua tham chiếu khi bạn gọi một phương thức trên loại giá trị. Ví dụ:
struct S
{
int x;
public S(int x) { this.x = x; }
public void M() { Console.WriteLine(this.x); }
}
Phương pháp M() là một cách logic điều tương tự như:
public static void M(ref S _this) { Console.WriteLine(_this.x); }
Bất cứ khi nào bạn gọi một phương pháp dụ về một cấu trúc, chúng tôi vượt qua một ref đến biến rằng là người nhận cuộc gọi.
Vậy điều gì xảy ra nếu người nhận không phải là biến? Sau đó, giá trị được sao chép vào biến tạm thời được sử dụng làm bộ thu. Và nếu giá trị lớn, đó có thể là một bản sao đắt tiền!
Loại giá trị được sao chép theo giá trị; đó là lý do tại sao chúng được gọi là các loại giá trị. Trừ khi bạn đang có kế hoạch là cực kỳ cẩn thận về việc tìm kiếm tất cả các bản sao đắt tiền có thể và loại bỏ chúng, tôi sẽ làm theo lời khuyên của hướng dẫn thiết kế khuôn khổ: giữ cấu trúc dưới 16 byte và chuyển chúng theo giá trị.
Tôi cũng nhấn mạnh rằng Jon nói đúng: chuyển một cấu trúc bằng ref có nghĩa là chuyển tham chiếu đến biến và các biến số có thể thay đổi. Đó là lý do tại sao chúng được gọi là "biến". Không có "const ref" trong C# theo cách có trong C++; ngay cả khi chính loại giá trị đó dường như là "không thay đổi" không có nghĩa là biến số giữ nó là không thay đổi. Bạn có thể thấy một ví dụ cực đoan về điều đó trong ví dụ mang tính giáo dục nhưng khó hiểu này:
struct S
{
readonly int x;
public S(int x) { this.x = x; }
public void M(ref S s)
{
Console.WriteLine(this.x);
s = new S(this.x + 1);
Console.WriteLine(this.x);
}
}
M có thể viết ra hai số khác nhau không? Bạn sẽ ngây thơ nghĩ rằng cấu trúc là bất biến, và do đó x không thể thay đổi. Nhưng cả hai s và này là biến, và biến có thể thay đổi:
S q = new S(1);
q.M(ref q);
Đó in 1, 2 vì this
và s
đều tham chiếu đến q
, và không có gì là dừng q
từ việc thay đổi ; không phải là chỉ đọc.
Tóm lại: nếu tôi có rất nhiều dữ liệu mà tôi muốn đi qua và đảm bảo chắc chắn rằng nó không thay đổi, tôi sẽ sử dụng một lớp, không phải là cấu trúc.Chỉ sử dụng một cấu trúc trong kịch bản đó nếu bạn có một vấn đề hiệu suất được chứng minh thực sự được giải quyết bằng cách làm cho nó là cấu trúc, hãy nhớ rằng các cấu trúc lớn có khả năng rất tốn kém để sao chép.
Cái gọi là cấu trúc bất biến có thể được hiển thị để có thể thay đổi ngay cả khi không có gì trong mã của chúng hợp tác trong đột biến như vậy. Ví dụ, mặc dù vị trí lưu trữ của 'KeyValuePair
- 1. Python: Khi nào một biến được truyền theo tham chiếu và khi nào theo giá trị?
- 2. Biến PHP có được truyền theo giá trị hoặc theo tham chiếu không?
- 3. Chuyển các loại tham chiếu theo giá trị trong C#
- 4. Truy cập các biến theo giá trị hoặc tham chiếu
- 5. Chỉ định giá trị mặc định cho loại tham chiếu
- 6. Truyền tham số biến đổi thuật toán std theo giá trị so với tham chiếu
- 7. Các đối số được truyền cho các phương thức theo tham chiếu hay giá trị?
- 8. Truyền vectơ theo tham chiếu
- 9. Javascript bằng tham chiếu và theo giá trị
- 10. Giá trị và các loại tham chiếu
- 11. Truyền số nguyên theo tham chiếu trong Python
- 12. Truyền đối tượng theo tham chiếu hoặc giá trị trong C#
- 13. Chuyển đổi loại C# theo tham chiếu thành loại không khớp theo tham chiếu
- 14. Java cho vòng lặp theo giá trị hoặc tham chiếu
- 15. Có bất kỳ quy tắc nào khi các giá trị JavaScript được sao chép theo tham chiếu chứ không phải theo giá trị không?
- 16. làm các câu lệnh ném bắt mặc định trong C++ qua giá trị hoặc tham chiếu
- 17. Hiển thị giá trị điểm theo mặc định trên ZedGraph
- 18. Các đối tượng ColdFusion có được thông qua tham chiếu hoặc theo giá trị không?
- 19. Thêm cột có giá trị không rỗng theo mặc định.
- 20. Chỉ truyền ArrayList làm giá trị và không tham chiếu
- 21. Giá trị mặc định của loại động?
- 22. Xử lý dữ liệu theo tham chiếu hoặc theo giá trị trong python
- 23. Lambda: Tại sao giá trị được ghi lại bởi giá trị const, nhưng giá trị theo từng tham chiếu không?
- 24. Biến delphi có được khởi tạo với giá trị theo mặc định không?
- 25. biến tham chiếu trong đối tượng theo nghĩa đen?
- 26. VB6 vượt qua theo giá trị và vượt qua tham chiếu
- 27. Chỉ định tham chiếu theo dereferencing con trỏ NULL
- 28. PostgreSQL - đặt một giá trị cell mặc định theo một giá trị của ô
- 29. Các loại được sắp xếp và đối số truyền theo giá trị
- 30. Giá trị không được khởi tạo so với giá trị null của các loại tham chiếu
có thể bạn cần phải suy nghĩ lại lý do của mình để quyết định giữa các cấu trúc và lớp học. –