2011年12月3日土曜日

[C#]CompareToの実装を楽にする


最近ちまちまとIComparableを実装していた。例えばこんなクラスがあったら、

public class Version
{
    public Version()
    {
    }
    
    public Version(int major, int minor, int build, int revision)
    {
        Major = major;
        Minor = minor;
        Build = build;
        Revision = revision;
    }
 
    public int Major { get; set; }
    public int Minor { get; set; }
    public int Build { get; set; }
    public int Revision { get; set; }
}

こんな風にIComparableを実装していく。

public class Version : IComparable, IComparable<Version>
{
    public Version()
    {
    }
 
    public Version(int major, int minor, int build, int revision)
    {
        Major = major;
        Minor = minor;
        Build = build;
        Revision = revision;
    }
 
    public int Major { get; set; }
    public int Minor { get; set; }
    public int Build { get; set; }
    public int Revision { get; set; }
 
    public int CompareTo(object obj)
    {
        return CompareTo(obj as Version);
    }
 
    public int CompareTo(T other)
    {
        if (other == null)
            return 1;

        int majorCompared = Major.CompareTo(other.Major);
        if (majorCompared != 0)
            return majorCompared;

        int minorCompared = Minor.CompareTo(other.Minor);
        if (minorCompared != 0)
            return minorCompared;

        int buildCompared = Build.CompareTo(other.Build);
        if (buildCompared != 0)
            return buildCompared;

        return Revision.CompareTo(other.Revison);
    }
}

3つぐらい実装したところで、面倒すぎて死ぬかと思った。しかも、比較対象が参照型だと、nullの判定まで必要でさらに面倒くさい。

そこで、ちょっと考えることにした。

どうしよう


どうせほとんどのクラスが、内部フィールドの単純な比較の合成なんだから、宣言的にそういうことをやってくれる汎用クラスを一つ作れば良い。

具体的には以下のような使い方をしたい。


[TestFixture]
public class ComplexComparerTest
{
    [Test]
    public void Comparer_Test()
    {
        var comparer = new ComplexComparer<Version>();
        comparer
            .Member(v => v.Major)
            .Member(v => v.Minor)
            .Member(v => v.Build)
            .Member(v => v.Revision)
            ;
  
        var ver_1_0_0_0 = new Version(1, 0, 0, 0);
        var ver_2_0_0_0 = new Version(2, 0, 0, 0);

        Assert.IsTrue(0 < comparer.Compare(ver_1_0_0_0, ver_2_0_0_0));
        Assert.IsTrue(0 > comparer.Compare(ver_2_0_0_0, ver_1_0_0_0));
    }
}

ラムダ式で比較に利用するメンバを設定するメソッド(Memberメソッド)を用意し、設定した順に比較が行われるようにしたい。


実装しよう

というわけで実装する。適当にメンバを用意する。


public class ComplexComparer<T> : IComparer, IComparer<T>
{
    public ComplexComparer<T> Member<TMember>(Expression<Func<T, TMember>> expression)
        where TMember : IComparable
    {
        // ここ実装
        return this;
    }

    public int Compare(object x, object y)
    {
        return Compare((T)x, (T)y);
    }

    public int Compare(T x, T y)
    {
        // ここ実装
        return 0;
    }
}

比較処理を順番に実行していけばいいんだから、比較デリゲートのリストを持つようにして、CompareToの中身を実装してしまおう。


public class ComplexComparer<T> : IComparer, IComparer<T>
{
    private readonly IList<Comparison<T>> _comparisons = new List<Comparison<T>>();

    public ComplexComparer<T> Member<TMember>(Expression<Func<T, TMember>> expression)
        where TMember : IComparable
    {
        // あとで実装
        return this;
    }

    public int Compare(object x, object y)
    {
        return Compare((T)x, (T)y);
    }

    public int Compare(T x, T y)
    {
        foreach (var comparison in _comparisons)
        {
            var compared = comparison(x, y);
            if (compared != 0)
                return compared;
        }

        return 0;
    }
}

あとはMemberメソッドで、比較デリゲートが追加されるようにするだけだ。


public ComplexComparer<T> Member<TMember>(Expression<Func<T, TMember>> expression)
        where TMember : IComparable
    {
        var compiled = expression.Compile();

        _comparisons.Add((x, y) => 
        {
            T xMember = compiled(x);
            T yMember = compiled(y);
   
            if (xMember != null)
                return xMember.CompareTo(yMember);
   
            if (yMember != null)
                return yMember.CompareTo(xMember) * -1;
   
            return 0;
        });

        return this;
    }

Compareメソッドにnullの場合の判定も入れておこう。


public int Compare(T x, T y)
    {
        if (x == null || y == null)
        {
            if (x != null) return 1;
            if (y != null) return -1;
            return 0;
        }
  
        foreach (var comparison in _comparisons)
        {
            var compared = comparison(x, y);
            if (compared != 0)
                return compared;
        }

        return 0;
    }



かんせい


public class ComplexComparer<T> : IComparer, IComparer<T>
{
    private readonly IList<Comparison<T>> _comparisons = new List<Comparison<T>>();

    public ComplexComparer<T> Member<TMember>(Expression<Func<T, TMember>> expression)
        where TMember : IComparable
    {
        var compiled = expression.Compile();

        _comparisons.Add((x, y) => 
        {
            T xMember = compiled(x);
            T yMember = compiled(y);
   
            if (xMember != null)
                return xMember.CompareTo(yMember);
   
            if (yMember != null)
                return yMember.CompareTo(xMember) * -1;
   
            return 0;
        });
        
        return this;
    }

    public int Compare(object x, object y)
    {
        return Compare((T)x, (T)y);
    }

    public int Compare(T x, T y)
    {
        if (x == null || y == null)
        {
            if (x != null) return 1;
            if (y != null) return -1;
            return 0;
        }
  
        foreach (var comparison in _comparisons)
        {
            var compared = comparison(x, y);
            if (compared != 0)
                return compared;
        }

        return 0;
    }
}

使ってみる

Versionクラスに実装してみる。

public class Version : IComparable, IComparable<Version>
{
    public Version()
    {
    }
 
    public Version(int major, int minor, int build, int revision)
    {
        Major = major;
        Minor = minor;
        Build = build;
        Revision = revision;
    }
 
    public int Major { get; set; }
    public int Minor { get; set; }
    public int Build { get; set; }
    public int Revision { get; set; }
 
    private static readonly ComplexComparer<Version> _comparer = 
        new ComplexComparer<Version>()
            .Member(v => v.Major)
            .Member(v => v.Minor)
            .Member(v => v.Build)
            .Member(v => v.Revision);
 
    public int CompareTo(object obj)
    {
        return CompareTo(obj as Version);
    }
 
    public int CompareTo(T other)
    {
        return _comparer.Compare(this, other);
    }
}

とてもすっきりしたし楽になった。これなら間違いも少なくなるだろう。めでたしめでたし。

まとめ


  • 内部の比較デリゲートに詰める処理をアレンジすればいろいろバリエーションが広がる。
  • Expressionは便利
  • 宣言的な書き方は楽だし間違いが少ない。

2011年9月26日月曜日

[映画]「ワイルド・スピード MEGA MAX」の感想

シリーズ通してアクションもストーリも無茶なところが魅力のワイルド・スピードですが、今回はもっと無茶苦茶だった。

車は吹っ飛びまくるし爆発しまくる。アクションの迫力は最高。

でもちょっと気になるのはストーリで、基本的に主人公たちは強盗団のとんでもない悪党なので、なんかシリアスなシーンになっても、感情移入できない。
その辺り、もっと何も考えずにド派手なカーアクションをスカッと観れるようになっていたほうが気持よく鑑賞できる気がする。

あと、筋肉ムキムキのマッチョマン二人が、暑苦しい殴り合いをするシーンがなかなか。

2011年9月19日月曜日

[AVA]SA58 Para カスタムめも


  • ロングレンジバレル
  • 人体工学グリップ
  • リコイルコントロールストック
ある程度連射可能な反動、集弾性で、今のところ一番扱い易い。

Paraの苦手な中距離以降の交戦でも、初弾の精度と、集弾性で戦える。また、エイムモードも具合がよくて、集弾性が向上するので使える。

[映画]「世界侵略: ロサンゼルス決戦」の感想


  • 2時間ずっと銃撃戦
  • 退却NO! 2-5! (NO RETREAT! 2-5!)
  • ミシェル・ロドリゲス いいですわね

最近流行りの?エイリアンが突然攻めてくる系の本作。
他の作品と違う点は、ひたすら現場目線で展開されるところだった。
この手の映画でありがちな、ペンタゴンとか研究機関で指揮官とか学者が出てくるシーンが無い。
ほとんど主人公の海兵隊の部隊の目線で展開され、未知の敵と死闘を繰り広げる。

あと、エイリアンが意外と強くない(強いけど)。海兵隊員のM4でも、撃ちまくると、なかなか倒れないけど倒せるし、火力もそれほど激烈ではない。
また、エイリアンもこちらの軍隊のような、組織・軍事的行動を取る。物陰に隠れながら進んできたり、味方をカバーしたり、海兵隊の装甲車には、重火器を持ちだして対抗するなど、人間の軍隊のような様子を見せるので、さながら戦争映画のような迫力ある戦闘になっていた。

戦闘シーン以外では、主人公となる海兵隊の小隊の中に最初にあった軋轢やわだかまりが、戦闘を通して徐々に解消されていく描画がうまくて、演出に花を添える。

海兵隊の宣伝映画かと思うほど、海兵隊がかっこよくて大活躍だが、空軍兵士として登場するミシェル・ロドリゲスもかっこいい。この人はほんとに女性兵士の役が似合うなあ。

[映画]「RED」の感想

  • テンポの良い コメディ・アクション
  • ブルース・ウィリス 強すぎ
引退した凄腕のおじいちゃん・おばあちゃんが暴れる話。ブルース・ウィリスは歳をとっても超人的な強さ。

特攻野郎Aチームみたいなハチャメチャ・アクションとか、ナイト・アンド・デイのような巻き込まれ型ロマンスとか。

主人公(ブルース・ウィリス)が、スピンするパトカーからスッと降りて、そのままハンドガンで反撃するシーンがすごかった。

2011年8月12日金曜日

[映画]「トランスフォーマー/ダークサイド・ムーン」の感想


  • 前作よりも落ち着いた内容
  • ディセプティコンってすごく弱いような...
  • メガトロンさん小物すぎ
前作は、最初から最後まで激しいアクションの連続で、みていると疲れを感じるほどだったけど、その辺りは少し落ち着いてみやすくなっていた。

圧倒的なアクションとCG、テンポの良い展開で2時間半と長めの上映時間も、楽しく過ごせた。
それにしてもメガトロンさんの情け無い姿が涙を誘った。

2011年7月24日日曜日

[AVA]「SA58 Para」カスタムメモ

  • ロングレンジバレル
  • 精密トリガー
  • 人体工学グリップ

各バレルの感想

ライフリング強化バレル
  • 連射が下がって制御しやすい
  • 照準が開くとなかなか戻らない
スペツナズエディション
  • 反動が軽減されて制御しやすい
  • 気になる横ブレ
  • 扱い易いが中途半端感が漂う
ロングレンジバレル
  • 強烈だけど割と素直な縦反動
  • 高いヘッドショット一撃率

2011年7月23日土曜日

[映画]「デジャヴ」の感想


  • 適度なSF感、適度なリアリティ
  • テンポの良い展開

後輩が「面白かった!」と言っていたのでDVDで観てみた。

最初から最後までテンポよく進むサスペンスアクションという感じで、所々で伏線を回収しながら結末に向かう展開がすごく良く出来ていて面白かった。

ちょっとSFテイストもあるけど、あくまで一要素として。
映画の内容的にこのSF要素は不可欠だけど、映画の面白さにはあまり関係がない。あと、SFを絡めながらも「なんでもあり」なものでなく、適度なリアリティがあるのでうまく映画を面白くしていた。

[映画]「ハリー・ポッターと死の秘宝 PART2 (3D)」の感想


  • 迫力の魔法バトル
  • 原作を知らないとよくわからない所がちょっとある
  • ヴォルデモートが小物っぽい
  • あんまり3Dの効果が感じられなかった
PART1が内容的にすごく退屈だったので、PART2の迫力のある魔法バトルはすごくよかった。
ただ、3Dの効果が薄くて、これなら2Dでも良かったかなという感想。

あまり細かいことを解説する作りになっていないので、原作を知らないとよくわからない部分がちょこちょこある。
映画は迫力の映像と大筋のストーリだけ楽しんで、細かいことが気になる人は、Wikipediaで補完すると満足できるかも。

ヴォルデモートはもっと「史上最悪の闇の魔法使い」の貫禄というか、威厳があって欲しかった... すごく小物っぽかったです。

2011年7月3日日曜日

[映画]「鋼の錬金術師 嘆きの丘(ミロス)の聖なる星」の感想


  • 指パッチンの人影薄いなあ
  • アクションシーンすげー
  • 特典(コミック11.5巻)がもらえました
アクションシーンの迫力がすごい。結構な割合でアクションシーンがあって、バリエーション豊かだったので楽しく鑑賞できた。
ストーリはハガレンらしい暗い感じながら、嫌な後味が残らなくてよかった。

それにしても賢者の石はなんでもありやな。

[映画]「127時間」の感想


  • サバイバル
  • ヒューマンドラマ
一人旅が趣味の男が崖から転落して手を挟まれ動けなくなり、死に直面して自分の人生に思いを巡らせながら必死に脱出を試みる。実話を元にした映画。

テンポの良い展開と演出で飽きることなく鑑賞できた94分間だった。
序盤に崖から転落してからはずっと同じ場所で必死にもがく姿と、回想シーンの繰り返しだが、豊富な演出で退屈しない。
終盤にちょっと強烈なシーンがあるので、ショッキングなシーンが苦手な方は要注意。

最近見た映画の中で一番面白かった。

[映画]「SUPER8」の感想


  • 少年たちの冒険
  • ボーイ・ミーツ・ガール
  • エイリアンパニック

スタンド・バイ・ミーに少年少女の恋愛をテイストして、エイリアンパニックの迫力と緊張感を混ぜたような印象を受けた。

基本的に面白かったけど、ちょっと終わり方にまとまりがないというか...
いろんな要素が混ざってて拡散しちゃった感じだった。

2011年6月21日火曜日

[映画] 「スカイライン-征服-」の感想


  • えっ?続くの?
  • インデペンデンス・デイと宇宙戦争(トム・クルーズの)を混ぜたような感じだなあ
  • 無人機やラプターとエイリアンの戦闘機が入り乱れる戦闘シーンがかっこいい

話はよくあるエイリアンが攻めてくるパニック系で、インデペンデンス・デイみたいな迫力のあるアクションシーンが見所だった。
エイリアン戦闘機と米軍の最新兵器が入り乱れる空中戦は大迫力。
ただ個人的に、若干今後の展開が心配な終わり方だった。

2011年4月2日土曜日

Azure

次の案件でAzureをやることに。

パフォーマンスチューニングが大変そうだ。

TFT 10.14 Peeba Comp

こちらのガイドの自分用まとめです。 https://www.reddit.com/r/CompetitiveTFT/comments/hraunp/tft_1014_break_the_meta_new_peeba_comp_set_35/ 難しいですが完成すると非常に強く、プレ...