Domanda

Sto cercando di rendere più fluente una parte del mio codice.

Ho un'estensione di stringa che crea una richiesta HTTP dalla stringa e restituisce la risposta come stringa. Quindi posso fare qualcosa come ...

string _html = "http://www.stackoverflow.com".Request();

Sto cercando di scrivere un'estensione che continuerà a provare la richiesta fino a quando non avrà esito positivo. La mia firma assomiglia a ...

public static T KeepTrying<T>(this Func<T> KeepTryingThis) {
  // Code to ignore exceptions and keep trying goes here
  // Returns the result of KeepTryingThis if it succeeds
}

Ho intenzione di chiamarlo in qualche modo come ...

string _html = "http://www.stackoverflow.com".Request.KeepTrying();

Purtroppo, sembra che non funzioni =). Ho provato prima a trasformarlo in una lambda, ma non sembra funzionare neanche.

string _html = (() => "http://www.stackoverflow.com".Request()).KeepTrying();

C'è un modo per fare quello che sto cercando di fare mantenendo la sintassi abbastanza fluente?  Suggerimenti molto apprezzati.

Grazie.

È stato utile?

Soluzione

Non puoi usare un gruppo di metodi per metodi di estensione o espressioni lambda. I ha scritto un blog su questo argomento .

Sospetto che potresti trasmettere a Func < string > :

string _html = ((Func<string>)"http://www.stackoverflow.com".Request)
                    .KeepTrying();

ma è piuttosto brutto.

Un'alternativa sarebbe cambiare Request () in return a Func e usare:

string _html = "http://www.stackoverflow.com".Request().KeepTrying();

O se vuoi mantenere semplice il metodo Request , aggiungi semplicemente un metodo RequestFunc :

public static Func<string> RequestFunc(this string url)
{
    return () => url.Request();
}

e quindi chiama:

string _html = "http://www.stackoverflow.com".RequestFunc().KeepTrying();

Altri suggerimenti

Perché non capovolgerlo?

  static T KeepTrying<T>(Func<T> func) {
        T val = default(T);
        while (true) {
            try {
                val = func();
                break;
            } catch { }
        }

        return val;
    }

    var html = KeepTrying(() => "http://www.stackoverflow.com".Request());

Che dire di migliorare la richiesta?

string _html = "http://www.stackoverflow.com".Request(RequestOptions.KeepTrying);

string _html = "http://www.stackoverflow.com".Request(RequestOptions.Once);

RequestOptions è un enum. Potresti anche avere più opzioni, argomenti di timeout, numero di tentativi ecc.

o

public static string RepeatingRequest(this string url) {
  string response = null;
  while ( response != null /* how ever */ ) {
    response = url.Request();
  }
  return response;
}

string _html = "http://www.stackoverflow.com".RepeatingRequest();

AFAIK puoi scrivere un metodo di estensione che estende un delegato Func < T > , ma il compilatore non sa cosa vuoi dire:

string _html = "http://www.stackoverflow.com".Request.KeepTrying(); // won't work

Ma se lanci esplicitamente il delegato funzionerà:

string _html = ((Func<string>)"http://www.stackoverflow.com".Request).KeepTrying(); // works

La domanda qui è se la leggibilità del codice è davvero migliorata in questo caso da un metodo di estensione.

Non scriverei un metodo di estensione per stringa. Usa un tipo più specifico, come Uri .

Il codice completo:

public static class Extensions
{
    public static UriRequest Request(this Uri uri)
    {
        return new UriRequest(uri);
    }

    public static UriRequest KeepTrying(this UriRequest uriRequest)
    {
        uriRequest.KeepTrying = true;
        return uriRequest;
    }
}

public class UriRequest
{
    public Uri Uri { get; set; }
    public bool KeepTrying { get; set; }
    public UriRequest(Uri uri)
    {
        this.Uri = uri;
    }

    public string ToHtml()
    {
        var client = new System.Net.WebClient();

        do
        {
            try
            {
                using (var reader = new StreamReader(client.OpenRead(this.Uri)))
                {
                    return reader.ReadToEnd();
                }
            }
            catch (WebException ex)
            {
                // log ex
            }
        }
        while (KeepTrying);

        return null;
    }

    public static implicit operator string(UriRequest uriRequest)
    {
        return uriRequest.ToHtml();
    }    
}

Chiamandolo:

 string html = new Uri("http://www.stackoverflow.com").Request().KeepTrying();
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top