2009-03-14 39 views
12

Tôi có đơn giản mã sau C#:Boxing khi sử dụng Generics trong C#

private Stack<Person> m_stack = new Stack<Person>(); 

public void Add<T>(T obj) 
    where T : Person 
{ 
    m_stack.Push(obj); 
} 

này sẽ tạo ra đoạn mã sau IL:

.method public hidebysig instance void 
      Add<(ConsoleApplication1.Person) T>(!!T obj) cil managed 
    { 
    // Code size  20 (0x14) 
    .maxstack 8 
    IL_0000: nop 
    IL_0001: ldarg.0 
    IL_0002: ldfld  class [System]System.Collections.Generic.Stack`1<class ConsoleApplication1.Person> ConsoleApplication1.Pool::m_stack 
    IL_0007: ldarg.1 
    IL_0008: box  !!T 
    IL_000d: callvirt instance void class [System]System.Collections.Generic.Stack`1<class ConsoleApplication1.Person>::Push(!0) 
    IL_0012: nop 
    IL_0013: ret 
    } // end of method Pool::Add 

Vì vậy, câu hỏi của tôi là ... tại sao đấm bốc? (IL_0008) Tôi có thể hiểu downcasting hoặc thậm chí biên dịch lỗi, nhưng tại sao boxing (Person là một kiểu tham chiếu ...)

Cảm ơn bạn trước!

Trả lời

4

Tôi tin rằng đó là ràng buộc chung của phương pháp thực hiện điều này với bạn - nhưng ...

Trong mọi trường hợp, không cần đến phương pháp chung. Chỉ cần viết nó như:

 
public void Add(Person person) 
{ 
    m_stack.Push(person); 
} 

Bạn sẽ thấy rằng IL được đơn giản hóa, và hoàn toàn tránh được vấn đề này. Nếu bạn đang ràng buộc với một loại tham chiếu cụ thể, bạn chỉ có thể sử dụng loại tham chiếu đó.

Điều này dễ hiểu hơn và rõ ràng hơn nhiều. Tôi muốn đề nghị tránh các cuộc gọi phương pháp chung chung, trừ khi nó thực sự cần thiết. Các phương thức chung làm cho lớp ít rõ ràng hơn, có nghĩa là ít có thể đọc và duy trì được trong thời gian dài và khó sử dụng hơn.

+0

@ Reed: Vâng, đây là cách tôi giải quyết vấn đề, nhưng tôi đã tò mò tại sao loại tham chiếu được đóng hộp (không có ý nghĩa) ... –

+0

Tôi nghĩ rằng đó là cách triển khai các phương thức chung. Chú ý rằng đó là boxing T, không phải là Person. Bạn không bao giờ boxing/unboxing lớp học của bạn, nhưng nó là một cái gì đó "thêm" mà kết thúc trong đó trong các cuộc gọi phương pháp chung chung. Không chắc chắn tại sao, mặc dù. –

30

Trích từ ECMA-335 phân vùng III 4,1

Nếu typeTok là một loại tài liệu tham khảo, hướng dẫn hộp không có gì.

nơi typeTok!! T trong trường hợp của bạn.

Tôi đoán là khi trình biên dịch biên dịch mã, nó luôn gọi hộp bất kể loại toán hạng có phải là kiểu tham chiếu hay không. Do ngữ nghĩa của hướng dẫn hộp, kết quả mong muốn luôn được đảm bảo.

+0

đây là câu trả lời đúng. – JaredPar

+0

+1 Công việc tốt theo dõi việc này. Thông tin tốt. Liệu lệnh này có bị loại bỏ bởi JIT hay không, hoặc liệu nó có gây ra một lệnh noop được bỏ lại tại chỗ không? –

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