func 처럼 행동 할 매개 변수가없는 메소드 얻기
-
03-07-2019 - |
문제
나는 내 코드의 일부를 더 유창하게 만들려고 노력하고 있습니다.
문자열에서 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();
구문을 상당히 유창하게 유지하면서 내가하려는 일을하는 방법이 있습니까? 제안은 대단히 감사했습니다.
감사.
해결책
확장 방법 또는 Lambda 표현식에는 메소드 그룹을 사용할 수 없습니다. 나 얼마 전에 이것에 대해 블로그를 작성했습니다.
나는 당신이 캐스팅 할 수 있다고 생각합니다 Func<string>
:
string _html = ((Func<string>)"http://www.stackoverflow.com".Request)
.KeepTrying();
그러나 그것은 꽤 불쾌합니다.
한 가지 대안은 변화하는 것입니다 Request()
에게 반품 기능 및 사용 :
string _html = "http://www.stackoverflow.com".Request().KeepTrying();
또는 당신이 보관하고 싶다면 Request
메소드 자체는 단순하고 a를 추가하십시오 RequestFunc
방법:
public static Func<string> RequestFunc(this string url)
{
return () => url.Request();
}
그리고 전화 :
string _html = "http://www.stackoverflow.com".RequestFunc().KeepTrying();
다른 팁
Why not turn this on its head?
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());
What about enhancing the Request?
string _html = "http://www.stackoverflow.com".Request(RequestOptions.KeepTrying);
string _html = "http://www.stackoverflow.com".Request(RequestOptions.Once);
RequestOptions
is a enum. You could also have more options, timeout arguments, number of retries etc.
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();
AFAIK you can write an extension method that extends a Func<T>
delegate, but the compiler doesn't know what do you mean:
string _html = "http://www.stackoverflow.com".Request.KeepTrying(); // won't work
But if you explicitly cast the delegate will work:
string _html = ((Func<string>)"http://www.stackoverflow.com".Request).KeepTrying(); // works
The question here it whether the code readability is really improved in this case by an extension method.
I wouldn't write an extension method for string. Use a more specific type, like the Uri
.
The full code:
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();
}
}
Calling it:
string html = new Uri("http://www.stackoverflow.com").Request().KeepTrying();