Как заставить метод без параметров действовать как Func <ReturnT> - PullRequest
2 голосов
/ 29 апреля 2009

Я пытаюсь сделать часть своего кода более беглой.

У меня есть расширение строки, которое делает HTTP-запрос из строки и возвращает ответ в виде строки. Так что я могу сделать что-то вроде ...

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

Я пытаюсь написать расширение, которое будет пытаться выполнить запрос, пока он не будет выполнен успешно. Моя подпись выглядит примерно так ...

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
}

Я собираюсь назвать это чем-то вроде ...

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

Увы, это не похоже на работу =). Сначала я попытался превратить его в лямбду, но это тоже не сработало.

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

Есть ли способ сделать то, что я пытаюсь сделать, сохранив синтаксис достаточно свободно? Предложения очень ценятся.

Спасибо.

Ответы [ 5 ]

4 голосов
/ 29 апреля 2009

Нельзя использовать группу методов для методов расширения или лямбда-выражений. Я писал об этом некоторое время назад .

Я подозреваю, что вы могли бы привести к Func<string>:

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

но это довольно противно.

В качестве альтернативы можно изменить Request() на return a Func и использовать:

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

Или, если вы хотите сохранить простой метод Request, просто добавьте метод RequestFunc:

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

, а затем позвоните:

string _html = "http://www.stackoverflow.com".RequestFunc().KeepTrying();
3 голосов
/ 29 апреля 2009

Почему бы не повернуть это с ног на голову?

  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());
1 голос
/ 29 апреля 2009

А как насчет усиления запроса?

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

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

RequestOptions - это перечисление. Вы также можете иметь больше опций, аргументов тайм-аута, количества повторных попыток и т. Д.

OR

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();
0 голосов
/ 29 апреля 2009

Я бы не стал писать метод расширения для строки. Используйте более конкретный тип, например Uri.

Полный код:

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

Называя это:

 string html = new Uri("http://www.stackoverflow.com").Request().KeepTrying();
0 голосов
/ 29 апреля 2009

AFAIK вы можете написать метод расширения, который расширяет делегат Func<T>, но компилятор не знает, что вы имеете в виду:

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

Но если вы явно разыграете, делегат будет работать:

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

Вопрос здесь заключается в том, действительно ли читаемость кода действительно улучшена в этом случае с помощью метода расширения.

...