Pasar una función de devolución de llamada a otra clase

91

Básicamente, estoy tratando de pasar un método a otra clase para que se llame más tarde, pero no puedo resolver esto en C # (todavía estoy demasiado acostumbrado a Objective-C).

public class Class1{

    private void btn_click(object sender, EventArgs e)
    {
        ServerRequest sr = new ServerRequest();
        sr.DoRequest("myrequest", myCallback);
    }

    public void myCallback(string str)
    {
    }
}

Luego, más adelante, quiero que mi clase ServerRequest básicamente active la función de devolución de llamada, ¿no es esto posible? (Básicamente estoy llamando a casa a un servidor para obtener una respuesta de inicio de sesión a mi software)

No he podido encontrar una manera de hacer esto con los delegados, recibo errores continuamente. Aquí está la otra clase:

public class ServerRequest
{
    public void DoRequest(string request, Delegate callback)
    {
        // do stuff....
        callback("asdf");
    }
}

¿Es esto posible en #? En Objective-C esto sería simple y solo haría algo como

[myObject performSelector(@selector(MyFunctionName)) withObjects:nil];
Geesu
fuente

Respuestas:

140

Puede pasarlo como Action<string>, lo que significa que es un método con un solo parámetro de tipo stringque no devuelve nada (vacío):

public void DoRequest(string request, Action<string> callback)
{
    // do stuff....
    callback("asdf");
}
Vidrio roto
fuente
¿Y cómo se llama DoRequest? ¿Pasas una cadena o un método?
Kokodoko
1
para otros curiosos sobre Action. aquí hay un consejo rápido. puede tener varios tipos de parms pero no retorno (para pasar solo miembros de c # Action <type1, .., typeN> no permite modificador en tipos Para pasar función, use Func <typeList> nuevamente sin modificador en ningún tipo el último tipo en el list es el tipo de retorno de la función en realidad Action y Func son una forma rápida de usar delegados simples
gg89
¡Haz que mi día sea simple y limpio!
isanjosgon
24
public class Class1
    {

        private void btn_click(object sender, EventArgs e)
        {
            ServerRequest sr = new ServerRequest();
            sr.Callback += new ServerRequest.CallbackEventHandler(sr_Callback);
            sr.DoRequest("myrequest");
        }

        void sr_Callback(string something)
        {

        }


    }

    public class ServerRequest
    {
        public delegate void CallbackEventHandler(string something);
        public event CallbackEventHandler Callback;   

        public void DoRequest(string request)
        {
            // do stuff....
            if (Callback != null)
                Callback("bla");
        }
    }
Jeroen
fuente
10

Primero debe declarar el tipo de delegado porque los delegados están fuertemente tipados:

public void MyCallbackDelegate( string str );

public void DoRequest(string request, MyCallbackDelegate callback)
{
     // do stuff....
     callback("asdf");
}
Wiktor Zychla
fuente
Esta es una gran solución si está utilizando la misma firma de método en muchos lugares de su código.
mtmurdock
4
Es una buena práctica comprobar siempre si el método de devolución de llamada no es nulo antes de llamarlo.
Maciej
4

Delegatees solo la clase base, por lo que no puede usarla así. Sin embargo, podrías hacer algo como esto:

public void DoRequest(string request, Action<string> callback)
{
     // do stuff....
     callback("asdf");
}
Robbie
fuente
2
Func<string>sería un método que devuelve una cadena; necesita unAction<string>
BrokenGlass
@BrokenGlass tienes razón mi mal - actualizado (he hecho +1 en tu respuesta)
Robbie
4

Puede cambiar su código de esta manera:

public delegate void CallbackHandler(string str);

public class ServerRequest
{
    public void DoRequest(string request, CallbackHandler callback)
    {
        // do stuff....
        callback("asdf");
    }
}
Marco
fuente
2

Lo que necesita es un delegado y una devolución de llamada. Aquí hay un buen artículo de MSDN que le mostrará cómo usar esta técnica en C #.

Maciej
fuente
2

Puede usar solo el delegado que sea mejor para las funciones de devolución de llamada:

public class ServerRequest
{
    public delegate void CallBackFunction(string input);

    public void DoRequest(string request, CallBackFunction callback)
    {
        // do stuff....
        callback(request);
    }
}

y consumir esto como a continuación:

public class Class1
    {
        private void btn_click(object sender, EventArgs e)
        {
            ServerRequest sr = new ServerRequest();
            var callback = new ServerRequest.CallBackFunction(CallbackFunc);
            sr.DoRequest("myrequest",callback);
        }

        void CallbackFunc(string something)
        {

        }


    }
Nirupam
fuente