Như những người khác đã lưu ý, bạn không thể có trường "ref to variable". Tuy nhiên, chỉ biết rằng bạn không thể làm điều đó có lẽ là không hài lòng; bạn có thể cũng muốn biết đầu tiên, tại sao không, và thứ hai, làm thế nào để có được xung quanh hạn chế này.
Lý do tại sao là bởi vì chỉ có ba khả năng:
1) Không cho phép lĩnh vực loại ref
2) Cho phép các lĩnh vực không an toàn của loại ref
3) Không sử dụng lưu trữ tạm thời nhóm cho các biến cục bộ (hay còn gọi là "ngăn xếp")
Giả sử chúng tôi cho phép các trường kiểu ref. Sau đó, bạn có thể làm
public ref int x;
void M()
{
int y = 123;
this.x = ref y;
}
và bây giờ y có thể được truy cập sau M
hoàn tất. Điều này có nghĩa là chúng tôi đang trong trường hợp (2) - truy cập this.x
sẽ sụp đổ và chết khủng khiếp vì lưu trữ cho y không còn tồn tại - hoặc chúng tôi đang trong trường hợp (3) và địa phương y
được lưu trữ trên thùng rác thu thập đống, không phải là bộ nhớ tạm thời.
Chúng tôi thích tối ưu hóa các biến cục bộ được lưu trữ trên hồ bơi tạm thời ngay cả khi chúng được chuyển qua ref và chúng tôi ghét ý tưởng bạn có thể để lại một quả bom thời gian xung quanh. Do đó, tùy chọn nó là: không có trường ref.
Lưu ý rằng đối với các biến cục bộ là các biến đóng kín của các hàm ẩn danh, chúng tôi chọn tùy chọn (3); các biến cục bộ đó không được cấp phát khỏi nhóm tạm thời.
Điều gì sau đó đưa chúng ta đến câu hỏi thứ hai: làm thế nào để bạn vượt qua nó? Nếu lý do bạn muốn một trường ref là tạo một getter và setter của một biến khác, điều đó hoàn toàn hợp pháp:
sealed class Ref<T>
{
private readonly Func<T> getter;
private readonly Action<T> setter;
public Ref(Func<T> getter, Action<T> setter)
{
this.getter = getter;
this.setter = setter;
}
public T Value { get { return getter(); } set { setter(value); } }
}
...
Ref<int> x;
void M()
{
int y = 123;
x = new Ref<int>(()=>y, z=>{y=z;});
x.Value = 456;
Console.WriteLine(y); // 456 -- setting x.Value changes y.
}
Và ở đó bạn đi. y
được lưu trữ trên gc heap, và x
là một đối tượng có khả năng nhận và đặt y
.
Lưu ý rằng CLR không hỗ trợ người dân địa phương và ref phương thức trả lại, mặc dù C# thì không. Có lẽ một phiên bản tương lai giả định của C# sẽ hỗ trợ các tính năng này; Tôi có prototyped nó và nó hoạt động tốt. Tuy nhiên, đây không phải là thực sự cao trong danh sách ưu tiên, vì vậy tôi sẽ không có được hy vọng của tôi.
CẬP NHẬT: Tính năng được đề cập trong đoạn trên được thực hiện cuối cùng cho thực tế trong C# 7. Tuy nhiên, bạn vẫn không thể lưu trữ một ref trong một trường.
Bạn có muốn mở rộng đoạn thứ hai một chút không? "một đối tượng có thể thay đổi lớn hơn" không hoàn toàn rõ ràng đối với tôi. Ngoài ra, StringWrapper sẽ hoạt động như thế nào nếu không có cách nào để giữ tham chiếu chuỗi trong một trường? –
Tôi đã đưa ra một ví dụ mà nên làm rõ. Như tôi đã nói, trong một thiết kế thực, StringWrapper có lẽ sẽ là một đối tượng kinh doanh đang nắm giữ nhiều hơn một chuỗi. –
Cảm ơn ý tưởng. Ví dụ của tôi có lẽ đã quá đơn giản vì tôi thực sự có một đối tượng (không phải là một chuỗi) trong mã thực của tôi mà tôi đang cố gắng gán theo tham chiếu. Hành vi mà tôi đang tìm kiếm là cho phép người dùng của một đối tượng có thể gán giá trị null cho đối tượng đã nói, hoặc thậm chí gán một cá thể mới của kiểu đó từ các phương thức của nó. Tôi vượt qua đối tượng trong thông qua các nhà xây dựng như là một phần của một số tiêm phụ thuộc và do đó, các phương pháp khác chỉ có thể nhìn thấy các đối tượng bằng cách truy cập vào một lĩnh vực. Nó có vẻ như những gì tôi muốn không thể đạt được mà là một sự xấu hổ. – Jamie