2015-10-10 18 views
7

Kiến thức của tôi this trong một phương thức mở rộng được chuyển thành biến số ref. Tôi có thể xác minh điều này bằng cách thực hiệnPhương pháp mở rộng và biến 'biến này' cục bộ

public static void Method<T>(this List<T> list) 
{ 
    list.Add(default(T)); 
} 

List<int> ints = new List<int>(new int[] { 1, 2, 3, 4, 5 }); 
ints.Method(); 

My List<int> ints hiện là 1, 2, 3, 4, 5, 0.

Tuy nhiên khi tôi làm

public static void Method<T>(this List<T> list, Func<T, bool> predicate) 
{ 
    list = list.Where(predicate).ToList(); 
} 

List<int> ints = new List<int>(new int[] { 1, 2, 3, 4, 5 }); 
ints.Method(i => i > 2); 

Tôi mong chờ của tôi List<int> ints3, 4, 5 nhưng vẫn còn nguyên. Tôi có thiếu một cái gì đó hiển nhiên?

+0

'list' không thông qua tham khảo, đó là một tài liệu tham khảo thông qua giá trị. Đi qua bí danh tham chiếu biến trong phương thức gọi bên trong callee cho phép bạn gán trực tiếp cho nó. – Lee

+0

Có sự khác biệt giữa "tham chiếu * bằng * tham chiếu" và "truyền * tham chiếu * a". Tham chiếu đến danh sách được truyền theo giá trị, có nghĩa là bạn có thể truy cập và sửa đổi danh sách, nhưng bạn không chạm vào biến ở bên ngoài cũng tham chiếu đến danh sách. –

+0

'(danh sách mới ()) Phương thức()' biên dịch => đối số không cần phải là biến ở tất cả => không giống 'ref'. –

Trả lời

5

Thông số phương pháp mở rộng this được truyền theo giá trị, không phải theo tham chiếu. Điều này có nghĩa là khi nhập phương thức mở rộng, bạn có hai biến trỏ đến cùng một địa chỉ bộ nhớ: ints gốc và tham số list. Khi bạn thêm một mục vào danh sách bên trong phương thức mở rộng, nó được phản ánh trong ints, bởi vì bạn sửa đổi một đối tượng được tham chiếu bởi cả hai biến. Khi bạn gán lại list, danh sách mới sẽ được tạo trên vùng được quản lý và các tham số của phương thức tiện ích mở rộng sẽ được đưa vào danh sách này. Biến số ints vẫn trỏ đến danh sách cũ.

3

Vâng, khi bạn cố gắng sửa đổi thuộc tính của một số cá thể lớp, bạn thậm chí không cần ref vì bạn đang sửa đổi cá thể thay vì tham chiếu đến nó.

Trong ví dụ này, bạn không cần ref từ khóa như bạn thay đổi sở hữu:

class MyClass 
    {    
     public int MyProperty { get; set; } 
    } 

    static void Method(MyClass instance) 
    { 
     instance.MyProperty = 10;      
    } 

    static void Main(string[] args) 
    { 
     MyClass instance = new MyClass(); 
     Method(instance); 

     Console.WriteLine(instance.MyProperty); 
    } 

Output: 10

Và đây bạn cần ref từ khóa bởi vì bạn làm việc với tài liệu tham khảo và không phải với ví dụ:

... 

    static void Method(MyClass instance) 
    { 
     // instance variable holds reference to same object but it is different variable 
     instance = new MyClass() { MyProperty = 10 }; 
    } 

    static void Main(string[] args) 
    { 
     MyClass instance = new MyClass(); 
     Method(instance); 

     Console.WriteLine(instance.MyProperty); 
    } 

Output: 0

Cũng giống như kịch bản của bạn, các phương thức mở rộng giống như phương thức tĩnh bình thường và nếu bạn tạo đối tượng mới bên trong phương thức thì bạn có thể sử dụng từ khóa ref (không thể cho phương thức mở rộng) hoặc trả về đối tượng này nếu không tham chiếu đến nó sẽ là mất đi.

Vì vậy, trong trường hợp thứ hai của bạn, bạn nên sử dụng:

public static List<T> Method<T>(this List<T> list, Func<T, bool> predicate) 
{ 
    return list.Where(predicate).ToList(); 
} 

List<int> ints = new List<int>(new int[] { 1, 2, 3, 4, 5 }); 
ints = ints.Method(i => i > 2); 

foreach(int item in ints) Console.Write(item + " "); 

Output: 3, 4, 5

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