Pergunta

Eu estou tentando fazer uma parte do meu código mais fluente.

Eu tenho uma extensão de cadeia que faz uma solicitação HTTP para fora da cadeia e retorna a resposta como uma string. Então eu posso fazer algo parecido ...

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

Eu estou tentando escrever uma extensão que vai continuar tentando o pedido até obter êxito. Minha assinatura é algo como ...

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
}

Eu pretendo chamá-lo de algo como ...

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

Infelizmente, isso não parece trabalho =). Eu tentei fazê-lo em um lambda primeiro, mas isso não parece que quer trabalhar.

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

Existe uma maneira de fazer o que eu estou tentando fazer, mantendo a sintaxe bastante fluente? Sugestões muito apreciada.

Graças.

Foi útil?

Solução

Você não pode usar um grupo de método para métodos de extensão ou expressões lambda. I escrevi sobre isso um tempo atrás.

Eu suspeito que você poderia lançar a Func<string>:

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

mas que é bastante desagradável.

Uma alternativa seria a mudança Request() a retorno a Func e uso:

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

Ou se você queria manter o próprio método Request simples, basta adicionar um método RequestFunc:

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

e, em seguida, ligue para:

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

Outras dicas

Por que não transformar isso em sua cabeça?

  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());

Que tal melhorar o Pedido?

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

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

RequestOptions é uma enumeração. Você também pode ter mais opções, os argumentos de tempo de espera, número de tentativas etc.

ou

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 você pode escrever um método de extensão que se estende um delegado Func<T>, mas o compilador não sabe o que quer dizer:

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

Mas se você converter explicitamente o delegado vai funcionar:

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

A questão aqui se a legibilidade do código é realmente melhorou, neste caso, por um método de extensão.

Eu não iria escrever um método de extensão para string. Use um tipo mais específico, como o Uri.

O código 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();
    }    
}

Chamá-lo:

 string html = new Uri("http://www.stackoverflow.com").Request().KeepTrying();
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top