Nói chung, khi bạn bật tối ưu hóa trong trình biên dịch C# it attempts to minimize the number of temporary/local variable storage slots used in methods. Do đó, bạn không nên quan tâm đến việc cố gắng giảm thiểu số lượng biến vì trình biên dịch sẽ làm điều đó cho bạn. Nếu không có tối ưu hóa, sẽ có một số khác biệt bởi vì mục tiêu có để nâng cao trải nghiệm gỡ lỗi và bảo toàn càng nhiều thông tin càng tốt.
Trong trường hợp cụ thể này, chính xác cùng một IL được phát ra cho cả hai phương pháp khi tối ưu hóa được bật.Dưới đây là một đoạn hoàn chỉnh bao gồm một kiểu giá trị và kiểu tham chiếu để so sánh:
using System;
public class C {
private static MyStruct NewStructLocal()
{
var s = new MyStruct();
return s;
}
private static MyStruct NewStructReturn()
{
return new MyStruct();
}
private static MyClass NewClassLocal()
{
var s = new MyClass();
return s;
}
private static MyClass NewClassReturn()
{
return new MyClass();
}
}
public struct MyStruct
{
public int I;
}
public class MyClass
{
public int I;
}
Và IL phát ra là:
.method private hidebysig static
valuetype MyStruct NewStructLocal() cil managed
{
// Method begins at RVA 0x2054
// Code size 10 (0xa)
.maxstack 1
.locals init (
[0] valuetype MyStruct
)
IL_0000: ldloca.s 0
IL_0002: initobj MyStruct
IL_0008: ldloc.0
IL_0009: ret
} // end of method C::NewStructLocal
.method private hidebysig static
valuetype MyStruct NewStructReturn() cil managed
{
// Method begins at RVA 0x206c
// Code size 10 (0xa)
.maxstack 1
.locals init (
[0] valuetype MyStruct
)
IL_0000: ldloca.s 0
IL_0002: initobj MyStruct
IL_0008: ldloc.0
IL_0009: ret
} // end of method C::NewStructReturn
.method private hidebysig static
class MyClass NewClassLocal() cil managed
{
// Method begins at RVA 0x2082
// Code size 6 (0x6)
.maxstack 8
IL_0000: newobj instance void MyClass::.ctor()
IL_0005: ret
} // end of method C::NewClassLocal
.method private hidebysig static
class MyClass NewClassReturn() cil managed
{
// Method begins at RVA 0x2082
// Code size 6 (0x6)
.maxstack 8
IL_0000: newobj instance void MyClass::.ctor()
IL_0005: ret
} // end of method C::NewClassReturn
Do đó như xa như hiệu suất là có liên quan, họ sẽ giống hệt nhau.
Trong trường hợp loại tham chiếu, đối tượng được tạo, tham chiếu được đặt ở trên cùng của ngăn xếp đánh giá và ngay lập tức được trả về từ đó.
Trong trường hợp loại giá trị, vị trí lưu trữ cục bộ được khai báo, giá trị ở vị trí lưu trữ được khởi tạo, giá trị được tải lại và sau đó được trả về. Điều này khá điển hình đối với các loại giá trị không phải là loại nguyên thủy.
Một mục tổng quát hơn để suy nghĩ là trong một phương pháp có độ phức tạp đáng kể, trình biên dịch tạo ra rất nhiều thời gian không tên mà không có tên có thể truy cập được cho lập trình viên. Xét về hiệu suất, lo lắng về việc có bao nhiêu biến cục bộ được đặt tên mà bạn có thể thấy trong mã là dành thời gian của bạn lo lắng về điều sai.
Note
Câu hỏi đặt ra đã làm thay đổi phần nào kể từ lần đầu tiên tôi đã viết câu trả lời này, tuy nhiên tôi nghĩ rằng tất cả các phân tích này vẫn đứng. Trong trường hợp cụ thể, cho bạn nhận được chính xác cùng một IL trong cả hai phương pháp khi biên dịch với tối ưu hóa. Biến cục bộ không ảnh hưởng đến IL phát ra. Bây giờ nếu bạn đã thêm nhiều biến cục bộ hơn cho các đối số khác, bạn sẽ có IL khác và sẽ cần phải kiểm tra việc tháo gỡ để xác định mức độ khác biệt đầy đủ.
Nó sẽ không thực sự làm một trong hai, bạn không cố gắng trả về 'newObject' trong khối đầu tiên. Và vì nó là kiểu tham chiếu, khi nó trả về 'new MyObject()' trong khối thứ hai, nó sẽ đơn giản trả về một tham chiếu tới phân bổ bộ nhớ có sẵn cho nó, vì vậy nó sẽ không tạo/hủy và thêm biến. –
@AlexeiLevenkov Không phải tất cả các tối ưu hóa. Một số tối ưu hóa được thực hiện bởi trình biên dịch C#. –
Tự hỏi tại sao nhận xét của tôi bị xóa ... Câu hỏi thậm chí nói * Trình biên dịch ** sẽ tối ưu hóa điều này *, vậy tại sao chúng ta nói về JIT thay vì IL? –