2009-06-22 15 views
5

Tengo dos métodos en C# 3.5 que son idénticos barra una llamada de función, en el siguiente fragmento, consulte clientController.GetClientUsername vs clientController.GetClientGraphicalUsernameEn C# 3.5, ¿cómo pasar qué método para invocar un objeto como un parámetro

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; 
    } 

¿hay alguna manera (delegados, lambda de?) que pueden pasar en cuyo método de clientController Quiero llamar?

Gracias!

+0

El ejemplo es una instancia de un problema genérico que he encontrado al refactorizar bloques de código que son idénticas llamadas a métodos diferentes de barra. En particular, parece que veo esto en las pruebas. –

Respuesta

7

Sure. Basta con definir un delegado de este modo:

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

Y luego pasarlo a su función y llamarla:

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; 
} 

llamar a la función con el delegado, que va a hacer esto:

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

func.Invocar ... estilo pobre ... – leppie

+2

¿Qué estás diciendo es estilo pobre? Pasando en el delegado? Estaba respondiendo la pregunta. ¿Llamar a ".Invoke()" en el delegado? Prefiero esa notación porque deja en claro que estás usando un delegado. –

+2

Estoy con Josh G, esto parece una solución bastante elegante para el problema, y ​​si se llama "func" con cuidado, está claro lo que está sucediendo –

0

Puede pasar un MethodInfo, que se puede buscar estáticamente. Sin embargo, estoy de acuerdo en que se puede requerir un rediseño.

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

Un delegado es una forma mucho mejor de hacer esto que reflexionar. –

9

Mientras que puede pasar un delegado como parámetro, sugiero ir con una ruta diferente. Encapsule el cuerpo de la declaración if que implica código común en otra función y llame a esa en ambas funciones.

Visual Studio tiene la función "Refactorizar -> Método de extracto" en el menú contextual. Puede completar uno de los cuerpos, seleccionar el cuerpo y usar esa característica para extraer un método de forma automática.

+0

Estoy de acuerdo, un rediseño sería mejor. – Enyra

+1

También estoy de acuerdo: ¡Rediseño! Ese es un caso típico en el que comienzas a complicar cosas que son simples. BESO. –

+0

Este es un consejo perfecto para programar en un estilo imperativo (especialmente si solo hay dos funciones posibles), pero el hecho de pasar la función permite una emulación bastante aceptable de la función de lenguaje funcional de la aplicación parcial. –

1

El tipo de una función está escrita como Func < enParam1, inParam2, ..., returnParam>. No estoy seguro de improviso si se pasan los parámetros "fuera" correctamente en tipos "Func", pero usted debería ser capaz de hacer su función como

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

"out" y "ref" no son legales en los argumentos de tipo. Deberá definir un nuevo tipo de delegado. –

0

¿Qué hay de pasar simplemente en una bandera booleana?

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

Buena idea; aunque prefiero el enfoque de delegado - menos código para comunicar el mismo intento –

+0

Cuando se le da la opción, prefiero evitar indicadores booleanos como este.Mueven la descripción funcional de la función que está llamando desde el nombre de la función a la lista de parámetros. (En este caso, el final de la lista de parámetros). Además, el significado del booleano no es evidente en el sitio de llamada; debe buscar el nombre del parámetro para descubrir qué significa. –

Cuestiones relacionadas