mẫu đầu tiên của bạn, mà tôi nghĩ là tốt nhất mà bạn có thể nhận được như xa như khả năng đọc đi
Tôi không nghĩ rằng bạn có thể cải thiện khi mà quy tắc xem xét C# liên quan đến biểu thức lambda. Điều đó nói rằng tôi nghĩ rằng vài cải tiến có thể được thực hiện.
Trước tiên, hãy mở rộng chức năng cho các loại biểu thức lambda khác. Bạn sẽ cần nhiều hơn Func<T>
loại để xử lý tất cả các trường hợp. Quyết định các loại biểu thức bạn phải xử lý là gì. Ví dụ: nếu bạn có loại Func<S, T>
(như trong câu hỏi của bạn - Bar
trên Foo
), có vẻ tốt hơn.So sánh này
myclass.GetMemberName(() => new Foo().Bar);
với
myclass.GetMemberName<Foo>(x => x.Bar);
tôi sẽ nói những quá tải sẽ làm gì:
//for static methods which return void
public static string GetMemberName(Expression<Action> expr);
//for static methods which return non-void and properties and fields
public static string GetMemberName<T>(Expression<Func<T>> expr);
//for instance methods which return void
public static string GetMemberName<T>(Expression<Action<T>> expr);
//for instance methods which return non-void and properties and fields
public static string GetMemberName<S, T>(Expression<Func<S, T>> expr);
Bây giờ chúng có thể được sử dụng không chỉ trong các trường hợp nêu trong ý kiến, chắc chắn có những chồng chéo kịch bản. Ví dụ: nếu bạn đã có phiên bản Foo
, thì sẽ dễ dàng hơn khi gọi quá tải thứ hai (Func<T>
) quá tải cho tên thuộc tính Bar
, như myclass.GetMemberName(() => foo.Bar)
.
Thứ hai, triển khai chức năng GetMemberName
phổ biến cho tất cả các tình trạng quá tải này. Phương thức tiện ích mở rộng trên Expression<T>
hoặc LambdaExpression
sẽ thực hiện. Tôi thích thứ hai để bạn có thể gọi nó ngay cả trong các kịch bản không được đánh máy mạnh. Tôi sẽ viết nó như thế này, from this answer:
public static string GetMemberName(this LambdaExpression memberSelector)
{
Func<Expression, string> nameSelector = null;
nameSelector = e => //or move the entire thing to a separate recursive method
{
switch (e.NodeType)
{
case ExpressionType.Parameter:
return ((ParameterExpression)e).Name;
case ExpressionType.MemberAccess:
return ((MemberExpression)e).Member.Name;
case ExpressionType.Call:
return ((MethodCallExpression)e).Method.Name;
case ExpressionType.Convert:
case ExpressionType.ConvertChecked:
return nameSelector(((UnaryExpression)e).Operand);
case ExpressionType.Invoke:
return nameSelector(((InvocationExpression)e).Expression);
case ExpressionType.ArrayLength:
return "Length";
default:
throw new Exception("not a proper member selector");
}
};
return nameSelector(memberSelector.Body);
}
Cuối cùng, GetMemberName
không phải là một tên tốt nếu bạn gọi nó là không mở rộng đường. expression.GetMemberName()
âm thanh hợp lý hơn. Member.NameFrom<int>(x => x.ToString())
hoặc MemberName.From<string>(x => x.Length)
vv là các tên mô tả hơn cho các cuộc gọi tĩnh.
Vì vậy, tổng thể lớp có thể trông giống như:
public static class Member
{
public static string NameFrom(Expression<Action> expr)
{
return expr.GetMemberName();
}
public static string NameFrom<T>(Expression<Func<T>> expr)
{
return expr.GetMemberName();
}
public static string NameFrom<T>(Expression<Action<T>> expr)
{
return expr.GetMemberName();
}
public static string NameFrom<T>(Expression<Func<T, object>> expr)
{
return expr.GetMemberName();
}
}
Và sử dụng:
var name1 = Member.NameFrom(() => Console.WriteLine());
var name2 = Member.NameFrom(() => Environment.ExitCode);
var name3 = Member.NameFrom<Control>(x => x.Invoke(null));
var name4 = Member.NameFrom<string>(x => x.Length);
ngắn gọn nhất và sạch sẽ.
Đối với tài sản và các lĩnh vực, nó có thể được chuyển thành một lớp vô danh và sau đó sử dụng phản ánh tên thành viên có thể được đọc, as shown here.
public static string GetMemberName<T>(T item) where T : class
{
if (item == null)
return null;
return typeof(T).GetProperties()[0].Name;
}
Gọi nó như
var name = GetMemberName(new { new Foo().Bar });
Nó nhanh hơn, nhưng có những quirks nhất định, giống như không phải là rất thân thiện với refactor, và không giúp đỡ trong trường hợp các phương pháp như các thành viên. Xem các chủ đề ..
Làm việc cho tôi .. –
Tôi không chắc chắn tôi làm theo bình luận của bạn, nó làm việc cho bạn mà không cần đúc đầu tiên để cụ thể 'Expression>' hoặc kiểu gọi này là thỏa đáng? –
mlorbetske
Câu trả lời của bạn làm việc cho tôi '((Biểu hiện>) (() => new Foo(). Bar)) GetMemberName()' –