[C#][開発環境]Visual Studioに入れておくと捗る7つのプラグイン
3月末までJava/C#を使ったプロジェクトに参加していたんですが、その時に使ってたVisualStudio 2008周りのプラグインとかをまとめておく。
Visual Studio系
CodeRush
CodeRush: IDE Productivity Tools for Visual Studio | DevExpress
リファクタリング系の機能を追加してくれる
- メソッドの抽出
- ローカル変数の抽出
- 変数をvarにしたり、その逆をしたり
SonicFileFinder
ファイルを開くのが簡単になる。Eclipseでいうと「リソースを開く」に相当する
http://www.jens-schaller.de/sonictools/sonicfilefinder/index.htm
metalscroll
Sublime Textの右に出てくるようなエディタの全体図がだせる。(ミニマップ)
変数をAlt+クリックすることで、参照も分かる。
ただし、意味までは見てないみたいなので、Eclipseのとは違う
※Code Compareと相性が悪い
Google Code Archive - Long-term storage for Google Code Project Hosting.
DPack
ファイル内のクラス検索、メソッド検索、プロパティ検索ができるようになる。
クラス検索は初期化が遅いので、大体はSonicFileFinderを使っているので、
メソッド検索しか使わない。
Windowsアプリ(おまけ)
時間や日付の変換
普通プログラム内で時間や日付を扱うと基本はintとかlongになって、それを人間が見やすいようにするには、「H:MM:SS」とか「MM:SS」に変換とかにするんだけど、SimpleDateFormatで変換かだとスレッドセーフじゃないからあーだこーだとか考える必要あるし、それにしたって毎回、同じようなのを書くのかと。
いや、Googleがそんな無駄なことをするはずがない!!
と思って、ドキュメント見てたらあったね「android.text.format.DateUtils」
DateUtils.formatElapsedTime(sec) // 18:02
時間に変換するときは自動で「H:MM:SS」にもしてくれるみたい。便利。
それ以外にも時間・日付をいい感じに変換してくれそうなメソッドがDateUtilsにはたくさんあるみたいなので、SimpleDateFormatを使うよりはいいかもしれない。
他のMedaipPlayerを止める
2012/1/31
下記の方法でも止められるみたいですが、GoogleはAudioManager#requestAudioFocus()の実装を推奨してるみたいなので、本エントリーは参考程度ですね。詳しくはHandling changes in audio output | Android Developersを参考にしてください。気が向いたらこれについて書くかもだけど
MediaPlayerを使ってて、ふと他のアプリがMediaPlayerが再生してたらどうやって止めたらいいのか疑問になったので調べてみた。
iPhoneユーザーの視点としては、どの音楽アプリを起動してもそっちが優先して動いて欲しい。要するにそれまで音楽再生をしていたアプリを止めて自分でコントロールしなおしたいわけだ。
標準の音楽再生アプリを調べてみたらbroadcastを投げれば止まるみたい
// 停止ボタンのキーダウン Intent stopIntent = new Intent(); stopIntent.setAction(Intent.ACTION_MEDIA_BUTTON); KeyEvent stopDown = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_STOP); stopIntent.putExtra(Intent.EXTRA_KEY_EVENT, stopDown); // Broadcast発行 sendOrderedBroadcast(stopIntent, null, new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { // 停止ボタンのキーアップ Intent i = new Intent(); i.setAction(Intent.ACTION_MEDIA_BUTTON); KeyEvent stopUp = new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MEDIA_STOP); i.putExtra(Intent.EXTRA_KEY_EVENT, stopUp); // Broadcast発行 sendOrderedBroadcast(i, null); } }, null, 0, null, null);
KEYCODE_MEDIA_STOPではなくKEYCODE_MEDIA_PLAY_PAUSEも試してみたけど、名前からわかるとおり再生/停止を切り替えるので、うまく使うのはめんどくさい。
やってる内容としてはウィジットの振りをしてBroadcastを投げてるイメージであってると思う。
一回目のIntentは停止ボタンのキーダウン。
sendOrderedBroadcast()内での二回目のIntentは停止ボタンのキーアップ。
キーダウンだけでいけるかと思っていたら、長押しの処理のために両方見ていてキーアップのBroadcastを投げないと、次のキーアップのイベントを受け付けてくれないようだ。
ちなみにsendOrderedBroadcast()*1の動作が良くわかっていないまま使ってるので、誰か詳しい人教えてくれるとうれしい。
まとめ
音楽プレイヤーがウィジットを持っていて、ACTION_MEDIA_BUTTONのインテントフィルターを使っていれば、どのプレイヤーでも止まるはず。
それぞれのサービスを使う必要もない(標準のはそもそも公開されていないし)ので、Intentサイコーってことだね
*1:sendOrderedBroadcast()を使わないと"RuntimeException():BroadcastReceiver trying to return result during a non-ordered broadcast"が発生する
Uriクラスのテストクラス
Uriクラスのメソッドで毎回混乱するから、テストメソッドを書いた。
public void testUri() { Uri uri = Uri.parse("content://anony@com.limelabo:77777/person/1?history=10#name"); assertEquals("//anony@com.limelabo:77777/person/1?history=10", uri.getSchemeSpecificPart()); assertEquals("anony@com.limelabo:77777", uri.getAuthority()); assertEquals("content", uri.getScheme()); assertEquals("anony", uri.getUserInfo()); assertEquals("com.limelabo", uri.getHost()); assertEquals(77777, uri.getPort()); assertEquals("/person/1", uri.getPath()); assertEquals("1", uri.getLastPathSegment()); assertEquals("history=10", uri.getQuery()); assertEquals("name", uri.getFragment()); assertEquals(2, uri.getPathSegments().size()); assertEquals("person", uri.getPathSegments().get(0)); assertEquals("1", uri.getPathSegments().get(1)); assertEquals("10", uri.getQueryParameter("history")); assertEquals(1, uri.getQueryParameters("history").size()); assertEquals("10", uri.getQueryParameters("history").get(0)); }
Problem 14
// コラッツ問題用の関数 def col(n:Long):Long = n match { case 1 => 1 case x if x % 2 == 0 => x / 2 case x if x % 2 == 1 => 3 * x + 1 } // 初期値から上記の関数を1になるまで適用したListを作成 def c(n:Int):List[Long] = { def _c(m:Long, l:List[Long]):List[Long] = { if (m == 1) { return 1::l } _c(col(m), m::l) } _c(n, Nil) } // 100万未満の数列数 val l = (1 until 1000000).map(c(_).size) // 0始まりなので、調整のために+1 l.indexOf(l.max) + 1
末尾関数を使ってる部分があんまりきれいじゃない気がする。
もう少しスマートになりそうな気配がある
Problem 28
GDDでこれ系の問題を解くのが面白いことに気付いたのと、Scalaの勉強のために最近Eulerをといている。
これ絶対あとで解けなくなるってのを残しておこう。
一応、ネタバレ注意ですね。
// 次の対角線上の数字への増加分 val l = 1 :: ((1 to 1001).filter(_%2==0).map(c=>List(c,c,c,c)).flatten.toList) // lを元に実際の体格洗浄の数字を作った値の合計 l.zipWithIndex.map(t=>l.take(t._2+1).sum).sum
変にこった作りな気がする。
これくらいなら力づくで解くようなプログラムを書きたい。