2009-06-22 31 views
5

Tôi có hai phương thức trong C# 3.5, giống hệt như một hàm gọi, trong đoạn dưới đây, hãy xem clientController.GetClientUsername vs clientController.GetClientGraphicalUsernameTrong C# 3.5, Làm thế nào để bạn vượt qua phương thức nào để gọi trên một đối tượng dưới dạng tham số

private static bool TryGetLogonUserIdByUsername(IGetClientUsername clientController, string sClientId, out int? logonUserId) 
    { 
     string username; 
     if (clientController.GetClientUsername(sClientId, out username)) 
     { 
      // ... snip common code ... 
     } 

     return false; 
    } 

    private static bool TryGetLogonUserIdByGraphicalUsername(IGetClientUsername clientController, string sClientId, out int? logonUserId) 
    { 
     string username; 
     if (clientController.GetClientGraphicalUsername(sClientId, out username)) 
     { 
      // ... snip common code ... 
     } 

     return false; 
    } 

Có cách nào (đại biểu, lamda?) Mà tôi có thể chuyển sang phương thức nào trên clientController mà tôi muốn gọi?

Cảm ơn!

+0

Mẫu là một ví dụ của một vấn đề chung mà tôi đã gặp phải khi tái cấu trúc các khối mã giống hệt nhau các lệnh gọi phương thức thanh. Đặc biệt, tôi dường như thấy chúng trong các bài kiểm tra. –

Trả lời

7

Chắc chắn. Chỉ cần xác định một đại biểu như vậy:

public delegate bool GetUsername(string clientID, out string username); 

Và sau đó vượt qua nó vào chức năng của bạn và gọi nó là:

private static bool TryGetLogonUserId(IGetClientUsername clientController, string sClientId, out int? logonUserId, GetUsername func) 
{ 
    string username; 
    if (func.Invoke(sClientId, out username)) 
    { 
     // ... snip common code ... 
    } 
    return false; 
} 

Để gọi hàm với các đại biểu, bạn sẽ làm điều này:

TryGetLogonUserId(/* first params... */, clientController.GetClientUsername); 
+2

func.Invoke ... kiểu nghèo ... – leppie

+2

Bạn đang nói gì là kiểu kém? Đi qua đại biểu? Tôi chỉ trả lời câu hỏi. Gọi ".Invoke()" trên đại biểu? Tôi thích ký hiệu đó vì nó làm rõ rằng bạn đang sử dụng một đại biểu. –

+2

Tôi với Josh G, điều này có vẻ khá là một giải pháp thanh lịch cho vấn đề, và nếu bạn đặt tên "func" cẩn thận rõ ràng những gì đang xảy ra –

0

Bạn có thể vượt qua số MethodInfo, có thể tra cứu tĩnh. Tuy nhiên, tôi đồng ý rằng có thể yêu cầu thiết kế lại.

private static readonly MethodInfo getRegularLogin = typeof(IGetClientUsername).GetMethod("GetClientUsername"); 
private static bool TryGetLogonUserIdByUsername(IGetClientUsername clientController, string sClientId, out int? logonUserId) 
{ 

    string username; 
    return TryGetLoginReflective(getRegularLogin, clientController, sClientId, out username, out logonUserId); 
} 

private static readonly MethodInfo getGraphicalLogin = typeof(IGetClientUsername).GetMethod("GetClientGraphicalUsername"); 
private static bool TryGetLogonUserIdByGraphicalUsername(IGetClientUsername clientController, string sClientId, out int? logonUserId) 
{ 
    string username; 
    return TryGetLoginReflective(getGraphicalLogin, clientController, sClientId, out username, out logonUserId); 
} 

private static bool TryGetLoginReflective(MethodInfo method, IGetClientUsername clientController, string sClientId, out string username, out int? logonUserId) 
{ 
    object[] args = new object[]{sClientId, null}; 
    if((bool)method.Invoke(clientController, args)) 
    { 
     // ... snip common code ... 
    } 
    logonUserId = ...; 

    username = (string)args[1]; 
    return false; 
} 
+0

Một đại biểu là một cách tốt hơn để đi về điều này hơn là sự phản ánh. –

9

Mặc dù bạn có thể chuyển giao đại biểu làm thông số, tôi khuyên bạn nên đi theo một tuyến đường khác. Đóng gói phần thân của câu lệnh if liên quan đến mã chung trong một hàm khác và gọi hàm đó trong cả hai hàm.

Visual Studio có tính năng "Refactor -> Extract Method" trong trình đơn ngữ cảnh. Bạn có thể chỉ cần điền vào một trong các cơ quan, chọn cơ thể và sử dụng tính năng đó để trích xuất một phương pháp ra khỏi nó một cách tự động.

+0

Tôi đồng ý, thiết kế lại sẽ tốt hơn. – Enyra

+1

Tôi cũng đồng ý: Thiết kế lại! Đó là một trường hợp điển hình, nơi bạn bắt đầu làm phức tạp những điều đơn giản. HÔN. –

+0

Đây là lời khuyên hoàn hảo cho lập trình theo kiểu bắt buộc (đặc biệt nếu chỉ có hai chức năng có thể), nhưng thực sự chuyển chức năng cho phép mô phỏng khá tốt về tính năng ngôn ngữ chức năng của ứng dụng một phần. –

1

Loại hàm được viết là Func < inParam1, inParam2, ..., returnParam>. Tôi không chắc chắn ngay nếu "out" các thông số được truyền đúng trong các loại "Func", nhưng bạn sẽ có thể để làm cho chức năng của bạn như

void TryGetLogon(Func<IGetClientUsername, string, out int?, bool> f) { 
    // ... 
    f(x, y, z, a); 
} 
// ... 
TryGetLogon(TryGetLogonUserIdByGraphicalUsername); 
+2

"out" và "ref" không hợp pháp trong các đối số kiểu. Bạn sẽ phải xác định một loại đại biểu mới. –

0

Làm thế nào về chỉ đơn giản là đi qua trong một lá cờ boolean?

private static bool TryGetLogonUserIdByUsername(
    IGetClientUsername clientController, 
    string sClientId, out int? logonUserId, bool graphical) 
{ 
    string username; 
    bool gotClient = false; 

    if (graphical) 
    { 
     gotClient = clientController.GetClientGraphicalUsername(
      sClientId, out username); 
    } 
    else 
    { 
     gotClient = clientController.GetClientUsername(
      sClientId, out username); 
    } 

    if (gotClient) 
    { 
       // ... snip common code ... 
    } 

    return false; 
} 
+0

Ý tưởng hay; mặc dù tôi thích cách tiếp cận của đại biểu - ít mã hơn để truyền đạt cùng ý định –

+0

Khi đưa ra tùy chọn, tôi thích tránh các cờ boolean như thế này.Chúng di chuyển mô tả chức năng của hàm bạn đang gọi từ tên hàm vào danh sách tham số. (Trong trường hợp này, phần cuối của danh sách tham số). Ngoài ra, ý nghĩa của boolean không rõ ràng tại callite-- bạn phải tra cứu tên tham số để tìm ra ý nghĩa của nó. –

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