Khi nào nên sử dụng trong vs vs vs


383

Có người hỏi tôi vào ngày khác khi họ nên sử dụng từ khóa tham số outthay vì ref. Mặc dù tôi (tôi nghĩ) hiểu sự khác biệt giữa từ khóa refouttừ khóa (đã được hỏi trước đó ) và lời giải thích tốt nhất dường như là ref== inout, một số ví dụ (giả thuyết hoặc mã) mà tôi luôn luôn nên sử dụng outvà không ref.

reflà tổng quát hơn, tại sao bạn muốn sử dụng out? Có phải chỉ là cú pháp đường?


18
Một biến được truyền vào sử dụng outkhông thể được đọc từ trước khi nó được gán. refkhông có hạn chế này. Vì vậy, có đó.
Corey Ogburn

17
Nói tóm lại, reflà cho vào / ra, trong khi outlà một tham số chỉ ngoài.
Tim S.

3
Chính xác thì bạn không nhận được gì?
tnw

4
Ngoài ra outcác biến CÓ được gán cho trong hàm.
Corey Ogburn

Cảm ơn Corey. Nhưng tôi đã không như vậy. Quan điểm của tôi là lợi ích của việc này là gì. Trên thực tế tôi cần một ví dụ cho thấy một kịch bản trong đó chúng ta có thể sử dụng tham số ref để đạt được chức năng không thể đạt được bằng cách sử dụng tham số và ngược lại.
Rajbir Singh

Câu trả lời:


399

Bạn nên sử dụng outtrừ khi bạn cần ref.

Nó tạo ra sự khác biệt lớn khi dữ liệu cần được sắp xếp lại, ví dụ như cho một quá trình khác, có thể tốn kém. Vì vậy, bạn muốn tránh sắp xếp lại giá trị ban đầu khi phương thức không sử dụng nó.

Ngoài ra, nó cũng hiển thị cho người đọc khai báo hoặc cuộc gọi xem giá trị ban đầu có liên quan (và có khả năng được bảo tồn) hay bị vứt đi.

Như một sự khác biệt nhỏ, một tham số out không cần phải được khởi tạo.

Ví dụ cho out:

string a, b;
person.GetBothNames(out a, out b);

trong đó GetBothNames là một phương thức để truy xuất hai giá trị nguyên tử, phương thức sẽ không thay đổi hành vi cho dù a và b là gì. Nếu cuộc gọi đến máy chủ ở Hawaii, sao chép các giá trị ban đầu từ đây sang Hawaii là một sự lãng phí băng thông. Một đoạn tương tự sử dụng ref:

string a = String.Empty, b = String.Empty;
person.GetBothNames(ref a, ref b);

có thể gây nhầm lẫn cho người đọc, vì có vẻ như các giá trị ban đầu của a và b có liên quan (mặc dù tên phương thức sẽ chỉ ra chúng không phải).

Ví dụ cho ref:

string name = textbox.Text;
bool didModify = validator.SuggestValidName(ref name);

Ở đây giá trị ban đầu có liên quan đến phương pháp.


5
"Đó không phải là trường hợp thực sự." - bạn có thể vui lòng giải thích rõ hơn những gì bạn muốn nói không?
peterchen

3
Bạn không muốn sử dụng refcho các giá trị mặc định.
C.Evenhuis

155
Đối với hậu thế: Một sự khác biệt khác dường như không ai khác đã đề cập, như đã nêu ở đây ; đối với một outtham số, phương thức gọi được yêu cầu để gán giá trị trước khi phương thức trả về. - bạn không phải làm bất cứ điều gì với tham số ref.
brichin

3
@brichins Vui lòng tham khảo phần 'bình luận (Bổ sung cộng đồng)' trong liên kết được đề cập bởi bạn. Đó là một lỗi được sửa trong tài liệu VS 2008.
Bharat Ram V

13
@brichins phương thức được gọi là bắt buộc để gán giá trị, không phải phương thức gọi. zverev.eugene đây là những gì đã được sửa trong tài liệu VS 2008.
Segfault

72

Sử dụng để biểu thị rằng tham số không được sử dụng, chỉ được đặt. Điều này giúp người gọi hiểu rằng bạn luôn khởi tạo tham số.

Ngoài ra, ref và out không chỉ dành cho các loại giá trị. Chúng cũng cho phép bạn đặt lại đối tượng mà kiểu tham chiếu đang tham chiếu từ bên trong một phương thức.


3
+1 Tôi không biết rằng nó cũng có thể được sử dụng cho các loại tham chiếu, câu trả lời rõ ràng rất hay, cảm ơn
Dale

@brichins: Không bạn không thể. outcác tham số được coi là không được gán khi nhập vào hàm. Bạn sẽ không thể kiểm tra giá trị của chúng cho đến khi bạn lần đầu tiên được gán một số giá trị - không có cách nào để sử dụng giá trị mà tham số có khi hàm được gọi.
Ben Voigt

Đúng, bạn không thể truy cập giá trị trước khi gán nội bộ. Tôi đã đề cập đến thực tế là chính tham số có thể được sử dụng sau này trong phương thức - nó không bị khóa. Điều này có thực sự nên được thực hiện hay không là một cuộc thảo luận khác nhau (về thiết kế); Tôi chỉ muốn chỉ ra nó là có thể. Cảm ơn bạn đã làm rõ.
brichins 27/12/13

2
@ ด ว ว: Nó có thể được sử dụng với các loại tham chiếu vì khi bạn truyền vào một tham số loại tham chiếu, những gì bạn đang truyền là giá trị của tham chiếu không phải là chính đối tượng. Vì vậy, nó vẫn là pass-by-value.
Tarik

38

Bạn đúng ở chỗ, về mặt ngữ nghĩa, refcung cấp cả chức năng "vào" và "ra", trong khi outchỉ cung cấp chức năng "ngoài". Có một số điều cần xem xét:

  1. outyêu cầu phương thức chấp nhận tham số PHẢI, tại một số điểm trước khi quay lại, gán giá trị cho biến. Bạn tìm thấy mẫu này trong một số lớp lưu trữ dữ liệu khóa / giá trị như Dictionary<K,V>, nơi bạn có các hàm như thế nào TryGetValue. Hàm này nhận một outtham số chứa giá trị sẽ là gì nếu được truy xuất. Nó sẽ không có ý nghĩa cho người gọi để vượt qua một giá trị vào chức năng này, vì vậy outđược sử dụng để đảm bảo rằng một số giá trị sẽ được trong biến sau khi cuộc gọi, ngay cả khi nó không phải là "thật" dữ liệu (trong trường hợp TryGetValuenơi chìa khóa không có mặt).
  2. outrefcác tham số được sắp xếp khác nhau khi xử lý mã interop

Ngoài ra, bên cạnh đó, điều quan trọng cần lưu ý là mặc dù các loại tham chiếu và loại giá trị khác nhau về bản chất của giá trị của chúng, mọi biến trong ứng dụng của bạn đều chỉ đến một vị trí của bộ nhớ chứa giá trị , ngay cả đối với các loại tham chiếu. Nó chỉ xảy ra rằng, với các loại tham chiếu, giá trị chứa trong vị trí của bộ nhớ là một giá trị khácvị trí bộ nhớ. Khi bạn chuyển các giá trị cho một hàm (hoặc thực hiện bất kỳ phép gán biến nào khác), giá trị của biến đó sẽ được sao chép vào biến khác. Đối với các loại giá trị, điều đó có nghĩa là toàn bộ nội dung của loại được sao chép. Đối với các loại tham chiếu, điều đó có nghĩa là vị trí bộ nhớ được sao chép. Dù bằng cách nào, nó sẽ tạo ra một bản sao của dữ liệu chứa trong biến. Sự liên quan thực sự duy nhất mà điều này giữ liên quan đến ngữ nghĩa chuyển nhượng; khi gán một biến hoặc truyền theo giá trị (mặc định), khi gán mới được thực hiện cho biến ban đầu (hoặc mới), nó không ảnh hưởng đến biến khác. Trong trường hợp các loại tham chiếu, có, các thay đổi được thực hiện cho thể hiệncó sẵn ở cả hai phía, nhưng đó là vì biến thực tế chỉ là một con trỏ đến một vị trí bộ nhớ khác; nội dung của biến - vị trí bộ nhớ - không thực sự thay đổi.

Đi qua với reftừ khóa nói rằng cả biến ban đầu tham số hàm sẽ thực sự trỏ đến cùng một vị trí bộ nhớ. Điều này, một lần nữa, chỉ ảnh hưởng đến ngữ nghĩa chuyển nhượng. Nếu một giá trị mới được gán cho một trong các biến, thì bởi vì các điểm khác đến cùng một vị trí bộ nhớ, giá trị mới sẽ được phản ánh ở phía bên kia.


1
Lưu ý rằng yêu cầu mà phương thức được gọi gán giá trị cho tham số out được thực thi bởi trình biên dịch c #, chứ không phải bởi IL bên dưới. Vì vậy, một thư viện được viết bằng VB.NET có thể không phù hợp với quy ước đó.
jmoreno

Âm thanh như ref thực sự tương đương với biểu tượng hội nghị trong C ++ (*). Tham chiếu passby trong C # phải tương đương với những gì C / C ++ gọi là con trỏ kép (con trỏ tới con trỏ), do đó ref phải truy xuất con trỏ thứ 1, cho phép phương thức được gọi truy cập vào vị trí bộ nhớ của đối tượng thực trong ngữ cảnh.
Đến vào

Tôi thực sự sẽ đề nghị một chính xác TryGetValuesẽ sử dụng refvà không outrõ ràng trong trường hợp không tìm thấy khóa.
NetMage

27

Nó phụ thuộc vào bối cảnh biên dịch (Xem ví dụ bên dưới).

outrefcả hai đều biểu thị biến đi qua tham chiếu, tuy nhiên refyêu cầu biến phải được khởi tạo trước khi được truyền, đây có thể là một sự khác biệt quan trọng trong bối cảnh Marshaling (Interop: UmanagedToManagedTransition hoặc ngược lại)

MSDN cảnh báo :

Đừng nhầm lẫn khái niệm chuyển qua tham chiếu với khái niệm các loại tham chiếu. Hai khái niệm không giống nhau. Một tham số phương thức có thể được sửa đổi bằng ref bất kể đó là kiểu giá trị hay kiểu tham chiếu. Không có quyền anh thuộc loại giá trị khi nó được thông qua tham chiếu.

Từ Tài liệu MSDN chính thức:

Các từ khóa ra làm cho các đối số được thông qua tham chiếu. Điều này tương tự với từ khóa ref, ngoại trừ việc ref yêu cầu biến được khởi tạo trước khi được thông qua

Từ khóa ref khiến một đối số được truyền bằng tham chiếu, không phải theo giá trị. Hiệu quả của việc truyền bằng tham chiếu là bất kỳ thay đổi nào đối với tham số trong phương thức được phản ánh trong biến đối số cơ bản trong phương thức gọi. Giá trị của một tham số tham chiếu luôn giống với giá trị của biến đối số cơ bản.

Chúng tôi có thể xác minh rằng out và ref thực sự giống nhau khi đối số được gán:

Ví dụ về CIL :

Hãy xem xét ví dụ sau

static class outRefTest{
    public static int myfunc(int x){x=0; return x; }
    public static void myfuncOut(out int x){x=0;}
    public static void myfuncRef(ref int x){x=0;}
    public static void myfuncRefEmpty(ref int x){}
    // Define other methods and classes here
}

trong CIL, các hướng dẫn myfuncOutmyfuncRefgiống hệt như mong đợi.

outRefTest.myfunc:
IL_0000:  nop         
IL_0001:  ldc.i4.0    
IL_0002:  starg.s     00 
IL_0004:  ldarg.0     
IL_0005:  stloc.0     
IL_0006:  br.s        IL_0008
IL_0008:  ldloc.0     
IL_0009:  ret         

outRefTest.myfuncOut:
IL_0000:  nop         
IL_0001:  ldarg.0     
IL_0002:  ldc.i4.0    
IL_0003:  stind.i4    
IL_0004:  ret         

outRefTest.myfuncRef:
IL_0000:  nop         
IL_0001:  ldarg.0     
IL_0002:  ldc.i4.0    
IL_0003:  stind.i4    
IL_0004:  ret         

outRefTest.myfuncRefEmpty:
IL_0000:  nop         
IL_0001:  ret         

nop : không hoạt động, ldloc : load local, stloc : stack local, ldarg : load argument, bs.s : nhánh để nhắm mục tiêu ....

(Xem: Danh sách hướng dẫn CIL )


23

Dưới đây là một số lưu ý mà tôi đã rút ra từ bài viết về mật mã này trên C # Out Vs Ref

  1. Nó chỉ được sử dụng khi chúng ta mong đợi nhiều đầu ra từ một hàm hoặc một phương thức. Một suy nghĩ về các cấu trúc cũng có thể là một lựa chọn tốt cho cùng.
  2. REF và OUT là các từ khóa chỉ ra cách dữ liệu được truyền từ người gọi đến callee và ngược lại.
  3. Trong dữ liệu REF vượt qua hai chiều. Từ người gọi đến callee và ngược lại.
  4. Trong dữ liệu Out chỉ truyền một cách từ callee đến người gọi. Trong trường hợp này nếu Người gọi cố gửi dữ liệu tới callee thì nó sẽ bị bỏ qua / từ chối.

Nếu bạn là một người trực quan thì vui lòng xem video yourTube này thể hiện sự khác biệt thực tế https://www.youtube.com/watch?v=lYdcY5zulXA

Hình ảnh dưới đây cho thấy sự khác biệt trực quan hơn

C # Ra Vs


1
one-way, two-waycác điều khoản có thể bị sử dụng sai ở đây. Chúng thực sự là cả hai chiều, tuy nhiên hành vi khái niệm của chúng khác nhau về các tham chiếu và giá trị của tham số
ibubi

17

Bạn cần sử dụng refnếu bạn có kế hoạch đọc và ghi vào tham số. Bạn cần sử dụng outnếu bạn chỉ có kế hoạch viết. Trên thực tế, outlà khi bạn cần nhiều hơn một giá trị trả về hoặc khi bạn không muốn sử dụng cơ chế trả lại bình thường cho đầu ra (nhưng điều này rất hiếm).

Có cơ chế ngôn ngữ hỗ trợ các trường hợp sử dụng. Refcác tham số phải được khởi tạo trước khi chúng được truyền cho một phương thức (nhấn mạnh vào thực tế là chúng được đọc-ghi) và outcác tham số không thể được đọc trước khi chúng được gán một giá trị và được đảm bảo được ghi vào cuối phương pháp (nhấn mạnh vào thực tế là chúng chỉ được viết). Trái với các nguyên tắc này dẫn đến lỗi thời gian biên dịch.

int x;
Foo(ref x); // error: x is uninitialized

void Bar(out int x) {}  // error: x was not written to

Chẳng hạn, int.TryParsetrả về a boolvà chấp nhận một out inttham số:

int value;
if (int.TryParse(numericString, out value))
{
    /* numericString was parsed into value, now do stuff */
}
else
{
    /* numericString couldn't be parsed */
}

Đây là một ví dụ rõ ràng về tình huống bạn cần xuất hai giá trị: kết quả số và liệu chuyển đổi có thành công hay không. Các tác giả của CLR đã quyết định lựa chọn outở đây vì họ không quan tâm đến những gì intcó thể có trước đây.

Đối với ref, bạn có thể nhìn vào Interlocked.Increment:

int x = 4;
Interlocked.Increment(ref x);

Interlocked.Incrementnguyên tử tăng giá trị của x. Vì bạn cần đọc xđể tăng nó, đây là một tình huống refphù hợp hơn. Bạn hoàn toàn quan tâm đến những gì xtrước khi nó được truyền đến Increment.

Trong phiên bản tiếp theo của C #, thậm chí sẽ có thể khai báo biến trong outcác tham số, thêm sự nhấn mạnh hơn nữa vào bản chất chỉ xuất ra của chúng:

if (int.TryParse(numericString, out int value))
{
    // 'value' exists and was declared in the `if` statement
}
else
{
    // conversion didn't work, 'value' doesn't exist here
}

Cảm ơn zneak cho phản ứng của bạn. Nhưng bạn có thể giải thích cho tôi tại sao tôi không thể sử dụng để đọc và viết một tham số không?
Rajbir Singh

@RajbirSingh, vì outcác tham số không nhất thiết phải được khởi tạo, vì vậy trình biên dịch sẽ không cho phép bạn đọc từ một outtham số cho đến khi bạn viết một cái gì đó cho nó.
zneak

zneak, tôi đồng ý với bạn Nhưng trong ví dụ dưới đây, một tham số out có thể được sử dụng như read and write: string name = "myName"; private void OutMethod (out chuỗi nameOut) {if (nameOut == "myName") {nameOut = "Rajbir Singh theo phương thức out"; }}
Rajbir Singh

1
@RajbirSingh, ví dụ của bạn không biên dịch. Bạn không thể đọc nameOuttrong iftuyên bố của mình vì nó chưa được chỉ định trước.
zneak

Cảm ơn @zneak. Bạn hoàn toàn đúng. Nó không biên dịch. Cảm ơn rất nhiều vì sự giúp đỡ của tôi và bây giờ nó có ý nghĩa với tôi :)
Rajbir Singh

7

outlà phiên bản hạn chế hơn của ref.

Trong phần thân phương thức, bạn cần gán cho tất cả các outtham số trước khi rời phương thức. Ngoài ra, một giá trị được gán cho một outtham số bị bỏ qua, trong khi refyêu cầu chúng phải được gán.

Vì vậy, outcho phép bạn làm:

int a, b, c = foo(out a, out b);

nơi refsẽ yêu cầu a và b được chỉ định.


Nếu bất cứ điều gì, outlà phiên bản ít ràng buộc hơn. refcó "kiện tiên quyết: biến chắc chắn được gán, hậu điều kiện: biến được chắc chắn giao", trong khi outchỉ có 'hậu điều kiện:. biến được chắc chắn giao"(Và như mong đợi, hơn là cần thiết của việc thực hiện chức năng với điều kiện tiên quyết ít hơn)
Ben Voigt

@BenVoigt: Đoán xem điều đó phụ thuộc vào hướng bạn nhìn vào :) Tôi nghĩ tôi có nghĩa là hạn chế về tính linh hoạt của mã hóa (?).
leppie

7

Làm thế nào nó nghe:

ra = chỉ khởi tạo / điền vào một tham số (tham số phải được sản phẩm nào) trả lại ra đồng bằng

ref = tham khảo, thông số tiêu chuẩn (có thể có giá trị), nhưng các chức năng có thể modifiy nó.


biến tham số có thể nhận được một giá trị, trước khi bạn truyền nó cho một phương thức.
Bence Végert

6

Bạn có thể sử dụng outtừ khóa theo ngữ cảnh trong hai ngữ cảnh (mỗi ngữ cảnh là một liên kết đến thông tin chi tiết), như một công cụ sửa đổi tham số hoặc trong khai báo tham số loại chung trong giao diện và đại biểu. Chủ đề này thảo luận về công cụ sửa đổi tham số, nhưng bạn có thể xem chủ đề khác này để biết thông tin về khai báo tham số loại chung.

Các outđối số nguyên nhân từ khóa để được thông qua tham khảo. Điều này giống như reftừ khóa, ngoại trừ refyêu cầu biến được khởi tạo trước khi nó được thông qua. Để sử dụng một outtham số, cả định nghĩa phương thức và phương thức gọi đều phải sử dụng outtừ khóa một cách rõ ràng . Ví dụ: C #

class OutExample
{
    static void Method(out int i)
    {
        i = 44;
    }
    static void Main()
    {
        int value;
        Method(out value);
        // value is now 44
    }
}

Mặc dù các biến được truyền dưới dạng outđối số không phải được khởi tạo trước khi được truyền, nhưng phương thức được gọi là bắt buộc để gán giá trị trước khi phương thức trả về.

Mặc dù refouttừ khóa gây ra hành vi thời gian chạy khác nhau, chúng không được coi là một phần của chữ ký phương thức tại thời điểm biên dịch. Do đó, các phương thức không thể bị quá tải nếu khác biệt duy nhất là một phương thức lấy một refđối số và phương thức kia lấy một outđối số. Ví dụ, đoạn mã sau sẽ không biên dịch: C #

class CS0663_Example
{
    // Compiler error CS0663: "Cannot define overloaded 
    // methods that differ only on ref and out".
    public void SampleMethod(out int i) { }
    public void SampleMethod(ref int i) { }
}

Quá tải có thể được thực hiện, tuy nhiên, nếu một phương thức lấy một refhoặc một outđối số và phương thức kia không sử dụng, như thế này: C #

class OutOverloadExample
{
    public void SampleMethod(int i) { }
    public void SampleMethod(out int i) { i = 5; }
}

Các thuộc tính không phải là biến và do đó không thể được truyền dưới dạng outtham số.

Để biết thông tin về việc truyền mảng, hãy xem Mảng sử dụng refout(Hướng dẫn lập trình C #).

Bạn không thể sử dụng refouttừ khóa cho các loại phương pháp sau:

Async methods, which you define by using the async modifier.

Iterator methods, which include a yield return or yield break statement.

Thí dụ

Khai báo một outphương thức là hữu ích khi bạn muốn một phương thức trả về nhiều giá trị. Ví dụ sau sử dụng outđể trả về ba biến với một lệnh gọi phương thức. Lưu ý rằng đối số thứ ba được gán cho null. Điều này cho phép các phương thức trả về giá trị tùy chọn. C #

class OutReturnExample
{
    static void Method(out int i, out string s1, out string s2)
    {
        i = 44;
        s1 = "I've been returned";
        s2 = null;
    }
    static void Main()
    {
        int value;
        string str1, str2;
        Method(out value, out str1, out str2);
        // value is now 44
        // str1 is now "I've been returned"
        // str2 is (still) null;
    }
}

6

Làm thế nào để sử dụng inhoặc outhoặc reftrong C #?

  • Tất cả các từ khóa trong C#có cùng chức năng nhưng với một số ranh giới .
  • in đối số không thể được sửa đổi bằng phương thức được gọi.
  • ref đối số có thể được sửa đổi.
  • ref phải được khởi tạo trước khi được người gọi sử dụng, nó có thể được đọc và cập nhật trong phương thức.
  • out đối số phải được sửa đổi bởi người gọi.
  • out các đối số phải được khởi tạo trong phương thức
  • Các biến được truyền dưới dạng inđối số phải được khởi tạo trước khi được truyền trong lệnh gọi phương thức. Tuy nhiên, phương thức được gọi có thể không gán giá trị hoặc sửa đổi đối số.

Bạn không thể sử dụng in, refouttừ khóa cho các loại sau đây của phương pháp:

  • Các phương thức Async mà bạn xác định bằng cách sử dụng công cụ asyncsửa đổi.
  • Các phương thức lặp , bao gồm một yield returnhoặc yield breakcâu lệnh.

5

Chỉ cần làm rõ về nhận xét của OP rằng việc sử dụng ref và out là "tham chiếu đến một loại giá trị hoặc cấu trúc được khai báo bên ngoài phương thức", đã được thiết lập không chính xác.

Hãy xem xét việc sử dụng ref trên StringBuilder, đây là loại tham chiếu:

private void Nullify(StringBuilder sb, string message)
{
    sb.Append(message);
    sb = null;
}

// -- snip --

StringBuilder sb = new StringBuilder();
string message = "Hi Guy";
Nullify(sb, message);
System.Console.WriteLine(sb.ToString());

// Output
// Hi Guy

Như được thêm vào này:

private void Nullify(ref StringBuilder sb, string message)
{
    sb.Append(message);
    sb = null;
}

// -- snip --

StringBuilder sb = new StringBuilder();
string message = "Hi Guy";
Nullify(ref sb, message);
System.Console.WriteLine(sb.ToString());

// Output
// NullReferenceException

4

Một đối số được truyền dưới dạng ref phải được khởi tạo trước khi truyền đến phương thức trong khi tham số out không cần phải được khởi tạo trước khi chuyển sang phương thức.


4

tại sao bạn muốn sử dụng

Để cho người khác biết rằng biến sẽ được khởi tạo khi nó trả về từ phương thức được gọi!

Như đã đề cập ở trên: "đối với một tham số out, phương thức gọi được yêu cầu để gán giá trị trước khi phương thức trả về ."

thí dụ:

Car car;
SetUpCar(out car);
car.drive();  // You know car is initialized.

4

Về cơ bản cả hai refoutđể truyền đối tượng / giá trị giữa các phương thức

Các từ khóa ra làm cho các đối số được thông qua tham chiếu. Điều này giống như từ khóa ref, ngoại trừ việc ref yêu cầu biến đó được khởi tạo trước khi nó được thông qua.

out : Đối số không được khởi tạo và nó phải được khởi tạo trong phương thức

ref : Đối số đã được khởi tạo và nó có thể được đọc và cập nhật trong phương thức.

Việc sử dụng các loại ref ref cho các loại tham chiếu là gì?

Bạn có thể thay đổi tham chiếu đã cho thành một thể hiện khác.

Bạn có biết không?

  1. Mặc dù các từ khóa ref và out gây ra hành vi thời gian chạy khác nhau, chúng không được coi là một phần của chữ ký phương thức tại thời điểm biên dịch. Do đó, các phương thức không thể bị quá tải nếu khác biệt duy nhất là một phương thức lấy tham số ref và phương thức kia lấy tham số.

  2. Bạn không thể sử dụng các từ khóa ref và out cho các loại phương pháp sau:

    • Các phương thức async mà bạn xác định bằng cách sử dụng công cụ sửa đổi async.
    • Các phương pháp lặp, bao gồm một tuyên bố lợi nhuận hoặc phá vỡ năng suất.
  3. Các thuộc tính không phải là biến và do đó không thể được truyền dưới dạng tham số.


4

Ghi chú thêm về C # 7:
Trong C # 7, không cần phải khai báo trước các biến sử dụng. Vì vậy, một mã như thế này:

public void PrintCoordinates(Point p)
{
  int x, y; // have to "predeclare"
  p.GetCoordinates(out x, out y);
  WriteLine($"({x}, {y})");
}

Có thể được viết như thế này:

public void PrintCoordinates(Point p)
{
  p.GetCoordinates(out int x, out int y);
  WriteLine($"({x}, {y})");
}

Nguồn: Có gì mới trong C # 7.


4

Vẫn cảm thấy cần một bản tóm tắt tốt, đây là những gì tôi nghĩ ra.

Tóm lược,

Khi chúng ta ở trong hàm , đây là cách chúng ta chỉ định điều khiển truy cập dữ liệu biến ,

in = R

out = phải W trước R

ref = R + W


Giải trình,

in

Hàm chỉ có thể ĐỌC biến đó.

out

Biến không được khởi tạo trước vì
chức năng PHẢI VIẾT trước nó trước khi ĐỌC .

ref

Chức năng có thể ĐỌC / VIẾT cho biến đó.


Tại sao nó được đặt tên như vậy?

Tập trung vào nơi dữ liệu được sửa đổi,

in

Dữ liệu chỉ phải được đặt trước khi nhập chức năng (in).

out

Dữ liệu chỉ phải được đặt trước khi rời khỏi chức năng (out).

ref

Dữ liệu phải được đặt trước khi nhập chức năng (in).
Dữ liệu có thể được đặt trước khi rời khỏi chức năng (out).


có lẽ (trong / out / ref) nên được đổi tên thành (r / wr / rw). hoặc có thể không, vào / ra là một phép ẩn dụ đẹp hơn.
tinker

0

Cần lưu ý rằng đó inlà một từ khóa hợp lệ kể từ C # ver 7.2 :

Công cụ sửa đổi tham số có sẵn trong C # 7.2 trở lên. Các phiên bản trước tạo lỗi trình biên dịch CS8107 ("Tính năng 'tham chiếu chỉ đọc' không khả dụng trong C # 7.0. Vui lòng sử dụng phiên bản ngôn ngữ 7.2 trở lên.") Để định cấu hình phiên bản ngôn ngữ trình biên dịch, xem Chọn phiên bản ngôn ngữ C #.

...

Các từ khóa trong gây ra các đối số được thông qua tham chiếu. Nó làm cho tham số chính thức trở thành bí danh cho đối số, phải là một biến. Nói cách khác, bất kỳ thao tác nào trên tham số đều được thực hiện trên đối số. Nó giống như các từ khóa ref hoặc out, ngoại trừ trong các đối số không thể được sửa đổi bằng phương thức được gọi. Trong khi các đối số ref có thể được sửa đổi, các đối số out phải được sửa đổi bằng phương thức được gọi và những sửa đổi đó có thể quan sát được trong ngữ cảnh gọi.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.