プログラムの事とか

お約束ですが「掲載内容は私個人の見解です」

ReactiveExtensionsのThrottleの中でOnNextを呼んではいけない

はいやらかしました

まずはこちらのコードでどうなるか

static Subject<int> _subject;
static void Main(string[] args)
{
    _subject = new Subject<int>();
    _subject.Subscribe(Func);
    _subject.OnNext(0);

    Console.ReadKey();
}
static void Func(int i)
{
    Console.WriteLine(i);
    if (i >= 10) return;
    _subject.OnNext(i + 1);
}

コンソールに0から10まで出力されます。問題無しです

つぎにSubscribeの前にThrottleを入れて試してみます

// 他は同じなので割愛
    _subject.Throttle(TimeSpan.FromSeconds(1)).Subscribe(Func);

コンソールには0しか出力されません

なぜか、はThrottleのソースを見ればすぐにわかります

github.com

上記リンクのOnNext_hasValue = true;としてその次のPropagate内のForwardOnNextの後でfalseにしています ForwardOnNextの先に私が書いたFuncがいるわけで、その関数を抜けた後に_hasValue = false;にしているのだからFunc内でいくら次の値を発行しても無視されます

(説明下手は読み手の想像力でカバーしてください)

Throttle後は別スレッドになるのは知っていたので呼びっぱなしで次を処理しているものだと思い込んでいました。反省。

「処理の失敗時に少し待ってリトライ」みたいな時に↑みたいな感じで書いてしまうんですよねー

ASP.NET Coreのルーティング 2.1 -> 2.2

基本的にわたしがやらかしたことを晒している本ブログですがまたやらかしたので報告します

ASP.NET Core 2.2がリリースされて日本のリージョンにも入ったので2.2を使いましょー

とりあえず準備はVisual Studio 2017で新規のASP.NET Core 2.2を作成

2.1のルーティングを確かめる

2.2で作りましたがまずは2.1のころの動作をチェックします

以下変更点だけ

Startup.cs

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}

HomeController.cx

public class HomeController : Controller
{
    public IActionResult Index() => View();

    [Route("[controller]/test/{id}")]
    public IActionResult Test(string id) => Ok();
}

Index.cshtml

@Context.Request.Host@Context.Request.Path
<a asp-controller="Home" asp-action="Test">test</a>

出力

localhost:44379/
<a href="/Home/Test">test</a>

2.2で動かしてみる

Startup.cs

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}

CompatibilityVersion.Version_2_2に変更するだけ

出力

localhost:44379/
<a href="">test</a>

hrefの中身が空になりました

変更点

docs.microsoft.com

ここにいろいろ書いてありますが

IRouter ベースのルーティングでは、BlogController が存在しない場合や ReadPost アクション メソッドがない場合でも、結果は常に /Blog/ReadPost/17 となります。 予想どおり、アクション メソッドが存在する場合は、ASP.NET Core 2.2 以降のエンドポイント ルーティングで /Blog/ReadPost/17 が生成されます。 しかし、アクションが存在しない場合は、エンドポイント ルーティングで空の文字列が生成されます。

Index.cshtmlのアンカータグヘルパーで書いたところ<a asp-controller="Home" asp-action="Test">test</a>idの指定がないのですが、2.1のころはあるものとしてリンクを生成して、2.2以降は無いからnullにする、ってことですね

idの指定をJavaScriptでしたいのでその前までのURLが欲しい!って思って使ってた私には効果が絶大でした

おまけ

なんとか致命傷で済んだのですが、ルーティングでもう一つやらかしてました

まずHomeController.csに少し手を加えます

HomeController.cx

public class HomeController : Controller
{
    public IActionResult Index() => View();

    [Route("[controller]/index/{id}")]
    public IActionResult Index(string id) => View();

    [Route("[controller]/test/{id}")]
    public IActionResult Test(string id) => Ok();
}

んでlocalhost:44379/home/index/1にアクセスすると

  • 2.1
localhost:44379/home/index/1
<a href="/Home/test/1">test</a>
  • 2.2
localhost:44379/home/index/1
<a href="">test</a>

これは2.1の動作が謎っぽいんですが、idが勝手に付与されてリンク生成するんですね

そしてそういうものだと思って使っていたので無事死亡しました

まとめ

例ではアンカータグヘルパーで試しましたがUrl.Action()なんかでも同じだよ!

CompatibilityVersion.Version_2_2の指定は計画的に


2018/12/27 追記

しばやん先生が分かりやすく解説してくれてます

blog.shibayan.jp

Math.Atan2というかdoubleでひっかかったこと

こにんちわC#初心者です

きょはわたしがさっきやらかしたことをかきます

static void Main(string[] args)
{
    Console.WriteLine($"Math.Atan2(0,0) = {Math.Atan2(0, 0)}");
    // Math.Atan2(0,0) = 0

    Console.WriteLine($"Math.Atan2(-0,-0) = {Math.Atan2(-0, -0)}");
    // Math.Atan2(0,0) = 0

    Console.WriteLine($"Math.Atan2((double)0,(double)0) = {Math.Atan2((double)0, (double)0)}");
    // Math.Atan2((double)0,(double)0) = 0

    Console.WriteLine($"Math.Atan2(-(double)0,-(double)0) = {Math.Atan2(-(double)0, -(double)0)}");
    // Math.Atan2(-(double)0,-(double)0) = -3.14159265358979

    Console.ReadKey();
}

4つ目 -0.0は0じゃないんですよ

雑魚ですみません