Moss’s blog

すごくなるためのブログ

Observable.FromEventについて調べてみた

最近、ReactiveExtensionsを勉強しています。(前回の投稿からかなり飛んでいる。。。) 調べながら進めていますが、ファクトリメソッドEventFromがわかりにくい。 丸覚えでもいいのですが、もう少し理解したいと思い調べてみました。(今更の記事感がありますが)

Observable.FromEventについて

まずは基本。シグネチャを定義から引用します。

IObservable<TEventArgs> FromEvent<TDelegate, TEventArgs>(
Func<Action<TEventArgs>, TDelegate> conversion, Action<TDelegate> addHandler, 
Action<TDelegate> removeHandler);

わかりにくい。。(私だけ?)

定型のコール

Observable.FromEvent<RoutedEventHandler, RoutedEventArgs>(
    h => (s, e) => h(e),
    h => button.Click += h,
    h => button.Click -= h
    ).Subscribe(e => textBlock.Text = string.Format("{0}: Ckicked",DateTime.Now));

ボタンクリックイベントを変換する処理。ボタンクリックされるとtextBlockのTextプロパティに日時を出力するサンプルです。

わかりにくい点

ここでわかりにくい点を挙げてみます。

  1. 第一引数は、=>が二つもあり複雑でわからない。
  2. サンプルすべての引数に「h」という変数が使われており、関連がかわらない。

わかりやすく書き換え

上記の点を踏まえて、わかりやすく書き換えてみます。

Observable.FromEvent<RoutedEventHandler, RoutedEventArgs>(
    handler1 => 
    {
        RoutedEventHandler action = (sender, e) =>
        {
            handler1(e);
        };
        var conversion = new RoutedEventHandler(action);
        return conversion;
    },
    handler2 => button.Click += handler2,   // 第一引数の戻り値
    handler2 => button.Click -= handler2     // 第一引数の戻り値
    ).Subscribe(e => textBlock.Text = string.Format("{0}: Ckicked", DateTime.Now));

以下の点が見えてきました。

  1. 第一引数にある2つの=>は、handlerA(key)を返却する(return)処理
  2. 第一引数のhと、第二第三引数のhは別物
  3. そしてhandlerAとは、Subscribeに渡すメソッドのこと。

処理の流れ

処理の流れをまとめてみま。画面からボタンをクリックしたとき以下の処理が実行されます。

  1. KeyPressが発行される。
  2. handlerBが実行される。
  3. handlerBが参照しているAction「handlerA(key)」が実行される。
  4. handlerAとは、Subscribeの引数で渡されるメソッド(value => Console.WriteLine("OnNext({0})", value))

シグネチャを改めて見てみる

IObservable<TEventArgs> FromEvent<TDelegate, TEventArgs>(
Func<Action<TEventArgs>, TDelegate> conversion, Action<TDelegate> addHandler, 
Action<TDelegate> removeHandler);

第一型引数: TDelegate

  • 購読するイベントのシグネチャ
  • Rx世界への変換前の型(イベント)

第二型引数: TEventArgs

  • Observerへ渡る引数の型
  • Rx世界への変換後の型(ストリームに流す型)

まとめ

  • FromEventは.NETのイベントをRxの世界に流すことのできる素敵なファクトリメソッド。
  • 第一型引数には、イベントシグネチャを指定します。
  • 第二型引数には、ストリームに流すデータの型を指定します。

省略記法が多用されているので、わかる人にはわかりやすいのだろうけど初めての人にはとっつきにくいものですね。 (私の慣れが足りていないということかな) 最後に全コードを記載しておきます。

using System;
using System.Reactive.Linq;
using System.Windows;

namespace RxStudyWpf
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            //Observable.FromEvent<RoutedEventHandler, RoutedEventArgs>(
            //    h => (s, e) => h(e),
            //    h => button.Click += h,
            //    h => button.Click -= h
            //    ).Subscribe(e => textBlock.Text = string.Format("{0}: Ckicked",DateTime.Now));


            Observable.FromEvent<RoutedEventHandler, RoutedEventArgs>(
                handler1 => 
                {
                    RoutedEventHandler action = (sender, e) =>
                    {
                        handler1(e);
                    };
                    var conversion = new RoutedEventHandler(action);
                    return conversion;
                },
                handler2 => button.Click += handler2,
                handler2 => button.Click -= handler2
                ).Subscribe(e => textBlock.Text = string.Format("{0}: Ckicked", DateTime.Now));
        }
    }
}
<Window x:Class="RxStudyWpf.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        Title="MainWindow" Height="150" Width="200">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <Button Grid.Row="0" Name="button" Content="Click"></Button>
        <TextBlock Grid.Row="1" Name="textBlock"></TextBlock>
    </Grid>
</Window>

参考:

blog.xin9le.net

LoggerFactoryの仕組みがわからない

以下のチュートリアルをやってみたが、.NET Coreバージョンが違うためコンパイルが通らない。

www.tutorialsteacher.com

以下のページに.NET Core 3.xでの方法があった。

stackoverflow.com

実装することでビルドは通るようになったものの肝心のログがコンソールへ出力されない。

Filterに何かあるのか。。

ASP.NET Coreのやり方はもっとシステマティックになっているようなので、そっちへ話を進めるか。。

QUESTION記事になったな。。

ブログを書くボリュームについて

I日、いろいろ調べて作ってると書きたいことがいっぱい出てくるが、

 

それをぜーんぶ書いてしまうと、まとまりの無い内容になってしまう気がする。

 

多分、消化度が低いのだろう。あと勉強したてだから、

 

「できたゼ!すごいやろう!( ̄∇ ̄)」

 

ってのも強いのだと思う。あと時間もかかる。

 

それよりも、もっと細かい内容を書く方が分かりやすいし、自分も見たい内容になる。

 

そして、それをまとめたものを、Qiitaなんかに書けばいい記事が作れる。

 

 

そんな気がした日でした。

 

 

Middlewareの追加方法

www.tutorialsteacher.com

Middlewareとは

  • ASP.NET CoreにはMiddlewareという仕組みがあります。
  • Middleware はざっくりとは「機能」と考えればよくて例えば「DefaultPageを生成する機能」「StaticFileを使用できるようにする機能」「カスタム機能」などなど。
  • クライアントから要求を受けたとき、その要求は「request pipeline」を通り、AppCodeへ到達します。
  • この request pipeline にMiddlewareをどんどん追加することで、サーバー機能を充実させることができます。
  • NuGet から追加もできるようです。
続きを読む

IoC-Container への挿入方法

  • Web APIチュートリアルを学習中に知ったことです。(間違っていたら指摘もらえると助かります。)

docs.microsoft.com

IoC Containerの大まかな理解。

  • 依存先を入れておくコンテナのイメージ。
  • そしてこのコンテナへ依存するオブジェクトを挿入する。(Dependency Injection)
  • アプリケーションはこのコンテナから挿入されているオブジェクトを参照することができる。
続きを読む

ASP.NET CoreでLINE BOTを作りたい

ASP.NET Coreで LINE BOTを作成したいので、とりあえずASP.NET Core Mvcテンプレートで作ろうとしてみた。

しかし、どうもここから必要なのは、このテンプレートWebアプリケーションにWEB API機能を追加することのよう。

んで、それをWebHookに渡す。ということだと思う。

Webアプリ自体をほぼしたことないので、MVCアプリだけでなくWeb APIについても調べんといかんらしい。

先は長いか。。