プログラムの事とか

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

Azure Maps Tileを使う

Azureのサービスの一つにAzure Mapsというのがあります

azure.microsoft.com

上記リンクの説明を見ると地理情報サービスって感じですが、地図サービスももちろんあります

独自(?)の地図コントロールも提供されています

azuremapscodesamples.azurewebsites.net

Bing MapsのころからMicrosoftの地図コントロールは出来が良かったのでこれも期待できそうです

Azure Mapsのタイルを使用する

ここからが本題

地図のタイルと言えばOpen Street Mapが有名ですね。Google Map高いからね、意識低い系企業さんなんかは「無料で使える地図」って認識で使うんですね。まぁそんなことしていたらOSS潰れちゃうから企業はちゃんと寄付なり課金なり自前サーバー立てるなりした方がいいと思います

ということでAzure Mapsつかいましょ。ざっくりした地図でいいならStandard S0で毎月25万トランザクション(15タイルで1トランザクション)の無料分がついてきます、かなり安いとおもいます

実際にOpen Street Mapと比較してみましょう

Azure Maps Tile

Azure Maps Tile

Open Street Map

Open Street Map

重ねてみる

f:id:puni-o:20190717111916j:plain

・・・昔を思い出しますね

まとめ

地図がスカスカなのはまだ我慢できるとして、幹線道路がずれているのは勘弁してほしいところです。今後このタイルが更新されるのか謎なんですが、更新してくれるんですかね?ゼンリンさんからデータ買い取ったりしてくれないですかね?

.NET側からP/Invokeで関数ポインターを渡したら落ちた話

不定期更新のやらかし投稿です。7Pay報道みて笑っている場合じゃなかった

やりたいこと

C#側(今回は.Net Core)からVC++のdllに関数ポインターを渡してdll側から呼んでもらう

実装

P/Invokeの具体的なのはググってください

ということでC#

class TestClass
{
    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    delegate void TestFunctionDelegate();
    [DllImport("test.dll", EntryPoint = "SetFunction", CallingConvention = CallingConvention.Cdecl)]
    static extern void SetFunction(TestFunctionDelegate function);
    public TestClass()
    {
        SetFunction(this.A);
    }
    private void A()
    {
    }
}

SetFunctionって関数でTestClass.A()ポインターを渡しているつもりです

何の問題もないと思うんですよねー、見た目ねー。これでしばらくしてからdll側から渡された関数ポインターを実行すると・・・

A callback was made on a garbage collected delegate...みたいなやつが出て落ちます。GCDelegateを消しているみたいですね

dnSpyで見てみる

ビルドしたアセンブリをdnSpyに突っ込んで上のコンストラクタ部分を見てみます

public TestClass()
{
    TestClass.SetFunction(new TestClass.TestFunctionDelegate(this.A));
}

そりゃGCで消されますよねー、ですよねー。Delegateわたしが楽ちんちんに書けるもSyntax sugarの一つだったのか

ということで修正

コンストラクタのあたりだけ

private TestFunctionDelegate _testFunctionDelegate;
public TestClass()
{
    _testFunctionDelegate = this.A;
    SetFunction(_testFunctionDelegate);
}

まとめ

これは知らなきゃ気づかないよー、ゆるしてくださいよ~~

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後は別スレッドになるのは知っていたので呼びっぱなしで次を処理しているものだと思い込んでいました。反省。

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