2011-11-08 30 views
5

Có thể chuyển tên mạnh của phương thức dưới dạng biểu thức lambda mà không cung cấp tham số và/hoặc dấu ngoặc đơn không?Sử dụng phương pháp gõ mạnh làm đối số mà không chỉ định tham số

Ví dụ, nếu tôi có phương pháp sau:

public class CalleeClass 
{ 
    public void MethodA(obj param1, obj param2) 
    { 
     ... 
    } 
} 

Tôi muốn gọi phương pháp này ở những nơi khác qua:

return new MyClass<CalleeClass>(c => c.MethodA); //Note: no()'s or arguments 

đâu MyClass sẽ chịu trách nhiệm cho, nói, MVC định tuyến bằng cách sử dụng tên phương thức làm đích. Mục đích ở đây là chúng ta muốn có thể sử dụng các khung nhìn mạnh mẽ được gõ thông qua các phương thức điều khiển và tôi không muốn phải cung cấp các tham số "câm" mà không được sử dụng.

Hiện tại, tôi đang sử dụng mã tương tự như sau để sử dụng tên phương thức, nhưng kiểu này vẫn yêu cầu truyền trong đối số giả và/hoặc dấu ngoặc đơn.

public void MyClass<T>(Expression<Action<T>> action) 
{ 
    var methodName = (action.Body as MethodCallExpression).Method.Name; 
} 

EDIT: Xin lỗi vì sự nhầm lẫn, nhưng tôi ban đầu đã cố gắng để đơn giản hóa vấn đề bằng cách chỉ bao gồm những gì tôi nghĩ bạn cần, và khi làm như vậy bỏ qua một số thông tin quan trọng. Mục tiêu cuối cùng ở đây là có MyClass nhận được một kiểu chung chung + biểu thức lambda, và biểu thức lambda có thể truyền vào tên phương thức gõ mạnh mà không tạo ra một đối tượng. -MB

+0

Bạn không thể đặt thông số tùy chọn? Ngoài ra: MethodCallExpression sẽ không hoạt động trừ khi nó có dấu ngoặc đơn tôi khá chắc chắn. – chemicalNova

+0

Các thông số không câm; chúng được sử dụng bởi trình biên dịch ... –

+0

Không vi phạm các tham số, nhưng chúng ta chỉ cần tên phương thức để định tuyến, và có vẻ lạ để tạo ấn tượng rằng chúng ta đang khởi tạo một đối tượng.Tôi không tin điều này thậm chí có thể, đó là lý do tại sao tôi đến đây. :) –

Trả lời

2

Bạn thực sự có thể vượt qua phương pháp này không có tham số:

class PassActionTest 
{ 
    public void Test() 
    { 
     var c = new C(); 
     var myClass = new MyClass(c.MethodA); 
    } 
} 

class MyClass 
{ 
    public MyClass(Action<object,object> action) 
    { 
     string methodName = action.Method.Name; 
    } 
} 

class C 
{ 
    public void MethodA(object param1, object param2) 
    { 
    } 
} 

EDIT: Theo EDIT Matt Beckman của, lớp chứa MethodA không nên được khởi tạo. Giải pháp mới của tôi là:

class PassActionTest 
{ 
    public void Test() 
    { 
     var myClass = new MyClass(c => c.MethodA); 
    } 
} 

class MyClass 
{ 
    public MyClass(Expression<Func<C, Action<object, object>>> expr) 
    { 
     UnaryExpression unaryExpr = (UnaryExpression)expr.Body; 
     MethodCallExpression methodCallExpr = (MethodCallExpression)unaryExpr.Operand; 
     ConstantExpression constantExpr = (ConstantExpression)methodCallExpr.Arguments[2]; 
     MethodInfo methodInfo = (MethodInfo)constantExpr.Value; 
     string methodName = methodInfo.Name; 
    } 

} 

class C 
{ 
    public void MethodA(object param1, object param2) 
    { 
    } 
} 

Hơi phức tạp khi phân tích biểu thức, nhưng tôi đã thử nghiệm và hoạt động.

+0

Trong cố gắng đơn giản hóa vấn đề ở đây, tôi nghĩ rằng tôi quên thêm rằng dòng này nên là: _return new MyClass (c => c.MethodA) _, vì tôi không muốn khởi tạo lớp có phương pháp MethodA. Xem các thay đổi ở trên. –

+0

@MattBeckman: Xem bản chỉnh sửa cho câu trả lời ban đầu của tôi. –

+1

Xem [nhận xét này] (http://stackoverflow.com/questions/8225302/get-the-name-of-a-method-using-an-expression#comment30751822_8228144) và [câu trả lời này] (http: // stackoverflow .com/a/26976055/1270174) để sử dụng trên thời gian chạy v4.5. –

0

Bạn có thể khai báo một delegate phù hợp với chữ ký của phương pháp MethodA() và sử dụng các đại biểu như các tham số cho constructor của lớp MyClass

public delegate void MethodADelegate(object param1, object param2); 

public MyClass(MethodADelegate methodParam) 
{ 
    //use the methodParam parameter 
} 

Ngoài ra, bạn có thể sử dụng Action <> đại biểu có mặt tại .Net theo đề xuất của @Olivier

1

Nếu bạn chỉ cần tên phương thức, tôi khuyên bạn nên sử dụng Delegate (http://msdn.microsoft.com/en-us/library/system.delegate.aspx) :

public MyClass(Delegate action) 
{ 
    var methodName = action.Method.Name; 
} 

này hoạt động ngoại trừ tôi nghĩ rằng bạn sẽ cần phải xác định loại đại biểu khi đi qua nó trong:

{ 
    ... 
    return new MyClass((Action<object,object>)c.MethodA); 
} 

này sẽ giữ cho nó tất cả mạnh mẽ, đánh máy như vậy refactoring sẽ làm việc, quá.

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