Func< ReturnT>のように動作するパラメータなしのメソッドの取得
-
03-07-2019 - |
質問
コードの一部をより流fluentにしようとしています。
文字列から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();
構文をかなり流whileに保ちながら、私がやろうとしていることを行う方法はありますか? 提案は大歓迎です。
ありがとう。
解決
拡張メソッドまたはラムダ式にメソッドグループを使用することはできません。私はこれについて少し前にブログ。
Func&lt; string&gt;
にキャストできると思われます:
string _html = ((Func<string>)"http://www.stackoverflow.com".Request)
.KeepTrying();
しかし、それはかなり厄介です。
1つの代替方法は、 Request()
をFuncに return に変更し、以下を使用することです。
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();
他のヒント
これを頭にしないのはなぜですか?
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());
リクエストの強化はどうですか?
string _html = "http://www.stackoverflow.com".Request(RequestOptions.KeepTrying);
string _html = "http://www.stackoverflow.com".Request(RequestOptions.Once);
RequestOptions
は列挙型です。より多くのオプション、タイムアウト引数、再試行回数などを設定することもできます。
または
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();
Acodeでは、 Func&lt; T&gt;
デリゲートを拡張する拡張メソッドを記述できますが、コンパイラはあなたが何を意味するのかわかりません:
string _html = "http://www.stackoverflow.com".Request.KeepTrying(); // won't work
ただし、明示的にデリゲートをキャストした場合は機能します:
string _html = ((Func<string>)"http://www.stackoverflow.com".Request).KeepTrying(); // works
ここでの質問は、この場合、拡張メソッドによってコードの可読性が本当に向上するかどうかです。
stringの拡張メソッドを作成しません。 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();