2012-06-16 28 views
18

Tôi muốn lấy tên của biến cục bộ (và tham số) tại thời gian chạy theo cách an toàn của trình tái cấu trúc. Tôi có phương pháp mở rộng sau:Lấy tên biến cục bộ (và tham số) tại thời gian chạy thông qua biểu thức lambda

public static string GetVariableName<T>(Expression<Func<T>> variableAccessExpression) 
{ 
    var memberExpression = variableAccessExpression.Body as MemberExpression; 
    return memberExpression.Member.Name; 
} 

... mà trả về tên của biến nắm bắt thông qua một biểu thức lambda:

static void Main(string[] args) 
{ 
    Console.WriteLine(GetVariableName(() => args)); 
    // Output: "args" 

    int num = 0; 
    Console.WriteLine(GetVariableName(() => num)); 
    // Output: "num" 
} 

Tuy nhiên, điều này chỉ hoạt động vì biên dịch C# thúc đẩy bất kỳ biến địa phương (và tham số) được ghi lại trong các hàm ẩn danh cho các biến mẫu có cùng tên trong lớp được tạo bởi trình biên dịch đằng sau hậu trường (theo Jon Skeet). Nếu trường hợp này không xảy ra, dàn diễn viên của Body đến MemberExpression sẽ không thành công, vì MemberExpression đại diện cho quyền truy cập trường hoặc thuộc tính.

Đây có phải là hành vi được lập tài liệu có thay đổi hay là chi tiết triển khai có thể thay đổi trong các phiên bản khác của khuôn khổ không?

Lưu ý: Câu hỏi này là tổng quát hóa my former one on argument validation.

+0

Bạn có thể nắm bắt các lựa chọn thay thế tại đây: http://stackoverflow.com/questions/72121/finding-the-variable-name-passed-to-a-function-in-c-sharp nhưng sau đó lại không có giấy tờ. Cách tiếp cận kiểu ẩn danh nhanh hơn nhiều mặc dù .. – nawfal

Trả lời

1

AFAIK, đây là chi tiết triển khai.

Tuy nhiên, tôi nghĩ bạn có thể đặt cược nó sẽ không thực sự thay đổi.

Tôi vừa thử nghiệm trong VS2012 RC và nó hoạt động như mong đợi - vì vậy bạn sẽ an toàn trong ít nhất vài năm.

+1

Còn Mono và các triển khai thay thế của khung công tác thì sao? Họ được biết là có một số quyền tự do với các chi tiết thực hiện (ví dụ, họ cung cấp [ngữ nghĩa lỏng lẻo hơn trên mô hình bộ nhớ] (http://stackoverflow.com/a/10608993/1149773) so với Khuôn khổ .NET). Ngay cả khi chúng xảy ra để sử dụng cùng một triển khai ngày hôm nay, chúng có thể không làm như vậy trong các bản phát hành trong tương lai. – Douglas

+1

Tuy nhiên, cảm ơn bạn đã kiểm tra trên VS2012 :-) Tốt để biết rằng ít nhất Microsoft sẽ không phá vỡ nó. – Douglas

+0

Tôi không biết về Mono - bạn sẽ phải kiểm tra. Đó là một quăng lên thực sự: bạn có nghĩ rằng cơ hội mà giải pháp của bạn sẽ phá vỡ lớn hơn cơ hội bạn sẽ nhận được lỗi của con người với 'CheckNotNull (" args ", args)' –

4

Đây là hành vi bạn nên không dựa vào.

Hãy xem Abuse of C# lambda expressions or Syntax brilliance?

Bây giờ đọc các ý kiến ​​từ Eric Lippert người sẽ tham gia nhóm thiết kế C#. Chúng bao gồm:

Tôi vừa hỏi Anders (và phần còn lại của nhóm thiết kế) những gì họ nghĩ. Hãy chỉ nói rằng kết quả sẽ không được in trên một tờ báo dành cho gia đình

Đối với lý do tại sao đây là kinh khủng, chúng ta có thể bắt đầu với unobvious, thông minh (hãy nhớ, thông minh là xấu , mã thông minh rất khó để duy trì), chứ không phải ở tất cả trong trường hợp sử dụng bằng cách thiết kế dự kiến ​​của các nhà thiết kế của lambdas, chậm, giòn, unportable, và không cần thiết

Từ những phát biểu này, tôi sẽ nói rằng nó sẽ không trở thành một hành vi được tài liệu hoặc được hỗ trợ.

+0

+1: Điều này đã chỉ cho tôi đúng hướng về câu trả lời sẽ là gì. Tuy nhiên, trong câu hỏi được liên kết, '.Attributes (style =>" width: 100% ")' lambda dường như chỉ được sử dụng bởi vì nó trông có vẻ thẩm mỹ/phong cách tốt hơn so với '.Attributes truyền thống (" style "," width: 100% ")' cú pháp, và không phải vì nó giới thiệu bất kỳ chức năng nào nếu không có sẵn, biện minh cho nhận xét của Lippert rằng nó là "không cần thiết". (tiếp theo ...) – Douglas

+3

Trong câu hỏi của tôi, tôi cảm thấy có một trường hợp sử dụng mạnh mẽ hơn để nhận tên thành viên/biến sử dụng lambdas. Tôi thấy rằng thực hành .NET của việc nhúng các tên thành viên/biến vào các chuỗi - chẳng hạn như 'PropertyChangedEventArgs' và' ArgumentException' - là "đáng kinh ngạc" hơn so với thay thế được đề xuất của tôi. – Douglas

+0

Prism4 sử dụng điều tương tự cho quá trình biểu hiện cây quá mức của nó của RaisePropertyChanged. – JKor

12

Cập nhật: Đây không còn là một vấn đề từ C# 6, trong đó đã giới thiệu các nhà điều hành nameof để giải quyết các tình huống như vậy (xem MSDN).

Có vẻ như câu trả lời cho câu hỏi của tôi là no; tính năng này không được chuẩn hóa. Tình hình có vẻ thậm chí còn khao khát hơn ban đầu tôi ngờ; không chỉ là thúc đẩy các biến bị bắt không được tiêu chuẩn hóa, mà còn là toàn bộ đặc điểm kỹ thuật của việc chuyển đổi các hàm ẩn danh thành các biểu diễn cây biểu thức của chúng.

Hàm ý của việc này là các chức năng ẩn danh thậm chí đơn giản, chẳng hạn như dưới đây, không đảm bảo dẫn đến cây biểu hiện nhất quán trên hiện thực khác nhau của khuôn khổ này (cho đến khi chuyển đổi được tiêu chuẩn hóa):

Expression<Func<int, int, int>> add = (int x, int y) => x + y; 

Các trích đoạn sau được lấy từ số C# Language Specification 4.0 (nhấn mạnh được thêm vào trong mọi trường hợp).

Từ “loại cây 4,6 Expression”:

Định nghĩa chính xác của các loại generic Expression<D> cũng như các quy tắc chính xác để xây dựng một cây biểu hiện khi một chức năng ẩn danh được chuyển thành một loại cây biểu thức, nằm ngoài phạm vi của đặc điểm kỹ thuật này và được mô tả ở nơi khác.

Từ “6.5.2 Thẩm định chuyển đổi chức năng ẩn danh với các loại cây khái niệm”:

chuyển đổi của một chức năng ẩn danh với một loại cây biểu thức tạo ra một cây biểu thức (§4.6). Chính xác hơn, việc đánh giá chuyển đổi hàm ẩn danh dẫn đến việc xây dựng một cấu trúc đối tượng đại diện cho cấu trúc của chính hàm ẩn danh đó. Cấu trúc chính xác của cây biểu thức, cũng như quy trình chính xác để tạo ra nó, được thực hiện xác định.

Ví dụ thứ ba trong “6.5.3 Ví dụ thực hiện” thể hiện việc chuyển đổi một chức năng ẩn danh cho phép chụp một biến địa phương, và khẳng định việc thúc đẩy biến đề cập trong câu hỏi của tôi:

Thời gian tồn tại của biến cục bộ bây giờ phải được kéo dài đến ít nhất là tuổi thọ của ủy nhiệm hàm ẩn danh. Điều này có thể đạt được bằng cách "nâng" biến cục bộ vào một trường của một trình biên dịch tạo ra lớp. Sự khởi tạo biến cục bộ (§7.15.5.2) sau đó tương ứng với việc tạo ra một cá thể của trình biên dịch tạo ra lớp, và truy cập biến cục bộ tương ứng với việc truy cập một trường trong cá thể của trình biên dịch tạo ra lớp.

này là tiếp tục chứng thực vào cuối phần:

Kỹ thuật tương tự áp dụng ở đây để nắm bắt các biến địa phương cũng có thể được sử dụng khi chuyển đổi chức năng ẩn danh để cây biểu thức: Tài liệu tham khảo cho các đối tượng biên dịch tạo có thể được lưu trữ trong cây biểu thức và truy cập vào các biến cục bộ có thể được biểu diễn dưới dạng truy cập trường trên các đối tượng này. Ưu điểm của phương pháp này là nó cho phép các biến cục bộ "nâng" được chia sẻ giữa các đại biểu và cây biểu thức.

Tuy nhiên, có một khuyến cáo tại trang đầu của bộ phận:

Việc thực hiện mô tả ở đây được dựa trên cùng một nguyên tắc được sử dụng bởi # biên dịch Microsoft C, nhưng nó được bởi không có nghĩa là một thực hiện bắt buộc, cũng không phải là người duy nhất có thể. Nó chỉ đề cập một cách ngắn gọn các chuyển đổi đối với các cây biểu thức, vì ngữ nghĩa chính xác của chúng nằm ngoài phạm vi của đặc tả này.

P.S. Eric Lippert confirms in this comment rằng thông số cây biểu thức chưa bao giờ được gửi. Có tồn tại một Expression Trees v2 Spec theo tài liệu DLR trên CodePlex, nhưng phạm vi của nó không xuất hiện để bao gồm việc chuyển đổi các hàm ẩn danh thành biểu thức cây trong C#.

+0

@ rally25rs: Điểm tốt. Giả định của tôi là Microsoft * do * có một đặc tả nội bộ mà họ tuân theo cho tất cả các triển khai của họ, nhưng họ đã chọn không cam kết làm cho nó được chuẩn hóa công khai. Có nghĩa là nó gần như chắc chắn là an toàn để giả định rằng các chuyển đổi dựa vào các phần khác của khung công tác (chẳng hạn như Linq2Sql) sẽ vẫn nhất quán; tuy nhiên, sự đảm bảo này không mở rộng đến các biểu thức nói chung (như biểu thức được đề cập trong câu hỏi của tôi để đọc các tên tham số). – Douglas

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