C#でのCollection系オブジェクトの受け渡し指針
C#でCollection系オブジェクト(IEnumerable, ICollection, IList等)の受け渡しをどうすべきか悩んでいた。 ListよりIList, EnumerableよりIEnumerableといった実装を含まないInterfaceが好ましいのは当然として、 あらゆるオブジェクトを想定してより抽象的なクラスを選択すべきというのは感覚的にわかるのだが、どうもしっくりこない。
以下の記事を見てなるほどと思った。 IEnumerable vs IReadOnlyList - Enterprise Craftsmanship
言語に依存しない一般的な方針としては、Postel’s law.として知られる(初めて知った...)
be conservative in what you send, be liberal in what you accept,
C#における具体的な方針として
prefer IEnumerable when accepting a collection; prefer IReadOnlyList when returning one.
確かに、引数は抽象的な方が使いやすいが、戻り値も抽象的だと結局toListしたりcastしたりしないといけないので使いにくいし、そもそもそんな使い方が正しいとは思えないので違和感があった。
IEnumerable - ICollection - IListという階層関係があるので、引数としてconservativeな(他の継承クラスも受け取れる)IEnumerableがよいというのはそのとおりだろう。 ただ、be liberal であるための解としてIReadOnlyListがあげられているが、これは利用側で内容を変更しないことがはっきりしている場合だろう。変更することが想定する場合はIListを返すべきと思われる。
複数のオブジェクトを格納する際には、IListの実装クラスがほとんどなので、これ以外を考慮する必要はとりあえずないと思われる。 DictionaryやHashtableを使う場合はIDictionaryあたりを返すのが妥当か?
CentOS 7のRedmine 4.0でrmagick build error.
CentOS7のDockerコンテナにてRedmineを構築中にrmagick buildにてエラー発生。 先週は動作したのだが...
ログを見ると、rmagickのバージョンは3.0.0で要求するImageMagickは6.8.9以上。インストールされているのは6.7.8Q16のためエラーとなっている。
このrmagick3.0.0は2月16日にリリースされたばかりらしい。その際に要求するImageMagickのバージョンが上がったのだろう。 rubygems.org
CentOSのリポジトリでは最新でも6.7しかない。remiリポジトリにあるようなのでインストールしたところ、buildエラーがなくなった。
rpm -ivh http://rpms.famillecollet.com/enterprise/remi-release-7.rpm yum -y install ImageMagick6 ImageMagick6-devel --enablerepo=remi
C#におけるIEnumerable,IEnumerator
IEnumerable(IEnumerator)はIListに比べると制約が多く、同じことをやろうとしても面倒、その分汎用性が高い、くらいに思ってました。
実際には、IEnumerableには要素の編集が一切できないのが最も大きな違いだと思います。
System.Linqを参照に追加すればIEnumerable.Appendが利用できますが、これはIList.Addとは違い非破壊的メソッドで自身は変更せずに要素を追加した新しいオブジェクトへの参照を返すだけです。 逆に言うと、一度設定したら編集しないCollectionを利用する場合はIEnumerableとして公開すればそとから編集されないことを保証できます。
Java(Android)のService, Application(Context)
AndroidにてActivityにまたがる処理を行う処理を記述するには、Bound Serviceを使う必要がある。bindeServiceの引数ServiceConnectionのコールバック関数onServiceConnectedにて渡されるIBinderでServiceオブジェクトを取得し、必要なメソッドを実行できる。
SQLiteへの保存処理をこれで行おうと考えたのだが、そのためのSQLiteOpenHelperにはContextが必須となっている。
ServiceはActivity(Contextを継承する)に依存したくないために利用しているので、そのままContextを取得できない。 必要なメソッドの引数に都度Contextを指定する手も無くはないが、メソッドが増えるほど面倒さが増すし、そもそもDatabaseへのconnectの条件としてcontextが必要なので、メソッドの呼び出しの都度Databaseへの再接続が発生してしまう。
ApplicationもContextを継承している。これならどこからでも呼び出せそうだが、Applicationインスタンスを取得するにはActivityのメソッドを呼び出す必要がある... ということで、Applicationを継承した独自クラスを作成し、Singletonとしてインスタンスを取得すると良いとわかった。よく使われている手法らしい。
これら独自Service, Applicationを利用する際の注意事項として、Application.manifestに宣言をしないといけない。これを忘れるとそれらをインスタンス化できずにnullになってExceptionが発生するが、エラー内容を一見してApplication.manifestが原因だとは判別できない。
Androidの各種メソッド・ライブラリには、この手のContext前提のものが多い。今回のSQLiteのライブラリに関しては内部で呼び出しているFileアクセスがContext前提となっているためのようだ。ただ、それがなぜContext前提にする必要があるかは理解できていない。C#のWPF, UWP関連でも似たような制限があった気がするので、現代的なアプリ開発には必要なセキュリティなどのための必須仕様なのかもしれない。
AndroidStudioでEmulatorが起動するも接続できない。
Android Studio 3.2.1(Windows64)にて、Emulataorが起動するのにアプリが全然起動しない状態になりました。
最下部にandroid waiting for target device to come online
と表示されたままで変化せず、LogcatのデバイスリストにはにはDisconnectedと表示される状態。
のMarkDubyaさんが言うように、adb kill-server
を実行したらアプリが起動し、Logcatにログが出力されるようになった。
Windows 10でのadb.exeはC:\Users\(ユーザー名)\AppData\Local\Android\Sdk\platform-tools
にあった。