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).biểu thức Lambda cho cấu trúc lại an toàn ArgumentExceptionLưu ý: Tham khảo “Getting names of local variables (and parameters) at run-time through lambda expressions” để biết khái quát về câu hỏi này cũng như một số câu trả lời.
Tôi thích ý tưởng của việc sử dụng biểu thức lambda để tạo triển khai cấu trúc lại an toàn của giao diện INotifyPropertyChanged
, sử dụng mã tương tự như cung cấp bởi Eric De Carufel.
Tôi đang thử nghiệm việc triển khai một cái gì đó tương tự để cung cấp tên thông số cho một ArgumentException
(hoặc các lớp dẫn xuất của nó) theo cách tái cấu trúc an toàn.
tôi đã xác định các phương pháp hữu ích sau đây để thực hiện null
kiểm tra:
public static void CheckNotNull<T>(Expression<Func<T>> parameterAccessExpression)
{
Func<T> parameterAccess = parameterAccessExpression.Compile();
T parameterValue = parameterAccess();
CheckNotNull(parameterValue, parameterAccessExpression);
}
public static void CheckNotNull<T>(T parameterValue,
Expression<Func<T>> parameterAccessExpression)
{
if (parameterValue == null)
{
Expression bodyExpression = parameterAccessExpression.Body;
MemberExpression memberExpression = bodyExpression as MemberExpression;
string parameterName = memberExpression.Member.Name;
throw new ArgumentNullException(parameterName);
}
}
Đối số xác nhận sau đó có thể được thực hiện một cách cấu trúc lại an toàn bằng cách sử dụng cú pháp sau:
CheckNotNull(() => arg); // most concise
CheckNotNull(arg,() => args); // equivalent, but more efficient
mối quan tâm của tôi nói dối trong các dòng sau:
Expression bodyExpression = parameterAccessExpression.Body;
MemberExpression memberExpression = bodyExpression as MemberExpression;
A MemberExpression
thể hiện “truy cập một trường hoặc thuộc tính”. Nó được đảm bảo hoạt động chính xác trong trường hợp INotifyPropertyChanged
, vì biểu thức lambda sẽ là quyền truy cập thuộc tính.
Tuy nhiên, trong mã của tôi ở trên, biểu thức lambda là một tham số ngữ nghĩa, không phải truy cập trường hoặc thuộc tính. Lý do duy nhất mã hoạt động là trình biên dịch C# thúc đẩy bất kỳ biến cục bộ nào (và các tham số) được ghi lại trong các hàm ẩn danh cho các biến mẫu trong một lớp do trình biên dịch tạo ra đằng sau hậu trường. Điều này được chứng thực bởi Jon Skeet.
Câu hỏi của tôi là: Hành vi này có phải là một chi tiết triển khai có thể thay đổi trong các triển khai thay thế hoặc các phiên bản tương lai của khung công tác không? Cụ thể, có thể có các môi trường nơi parameterAccessExpression.Body is MemberExpression
trả lại false
?
Điều gì về 'CheckNotNull (() => ((đối tượng) 5) dưới dạng chuỗi);'? – leppie
Cá nhân tôi quyết định rằng bất cứ điều gì 'Contract.Requires' nào là đủ tốt cho tôi. Nếu điều kiện tiên quyết thất bại, đó là lỗi. Không cần phải băn khoăn về các chi tiết. –
CodesInChaos
@CodeInChaos: Còn thư viện sẽ được cung cấp để tiêu thụ cho bên thứ ba thì sao? Dự kiến rằng các phương thức công khai sẽ thực hiện kiểm tra đối số và ném 'ArgumentException' với tên thông số chính xác. – Douglas