Quantcast
Channel: ささいなことですが。
Viewing all articles
Browse latest Browse all 104

拡張メソッドで、あれ?って思ったこと

$
0
0

あれ?って思ったことシリーズ第二弾。

つい先日、Cで書かれた組み込み機器と通信するプログラムをC#で書きました。
で、テストを書くときに、@neueccさんのChaining Assertionを使いました。
これは、Assert書くのを気持ちよくしてくれるライブラリです。

こんな感じ。

int actual = 0;
            
//普通はこう書くけど
Assert.AreEqual(actual, 0);

//こんな感じで書ける
actual.Is(0);

int以外の場合にコンパイルエラー

冒頭でも書きましたが、その日の僕はCで書かれた組み込み機器と通信するプログラムを作っていました。受け渡しするデータはBYTE、WORD、DWORDなわけですよ。で、C#側でもbyte、ushort、uintって出てくるわけですね。で、それに対して次のようなコードを書くとですね・・・

byte actual = 0;
actual.Is(0);

f:id:ishikawa-tatsuya:20150516181208p:plain
えー、なんでやねん・・・ってことになります。

Chaining Assertionの定義はこんな感じです。

publicstaticvoid Is<T>(this T actual, T expected, string message = "")

これって、第一引数のTが既にbyteだから第二引数の0に関してはbyte扱いしてくれても良さそうですよね。っていうか、これ実は拡張メソッドでなければコンパイル通るんです。

void Func<T>(T t1, T t2) { }

[TestMethod]
void Test()
{
    byte actual = 0;
    //これはOK。ほら、分かってるじゃん!
    Func(actual, 0);
}

でも、拡張にしたらコンパイルエラー

publicstaticclass Ex
{
    publicstaticvoid Func<T>(this T t1, T t2) { }
}

[TestClass]
publicclass ExTest
{
    [TestMethod]
    void Test()
    {
        byte actual = 0;
        //コンパイルエラー//分かっておくれよ・・・
        actual.Func(0);
    }
}

しかも、これint以外は全滅かと思いきや、いけるのもあるw。なんでlongとかいけてるんだろ?
×がついているのはコンパイルエラーになります。

//×byte by = 0;
by.Is(0);

//×short s = 0;
s.Is(0);

//×ushort us = 0;
us.Is(0);

int i = 0;
i.Is(0);

//×uint ui = 0;
ui.Is(0);

long l = 0;
l.Is(0);

//×ulong ul = 0;
ul.Is(0);

float f = 0;
f.Is(0);

double d = 0;
d.Is(0);

decimal dec = 0;
dec.Is(0);

まあ、数値を型にするの色々ルールあるし、なんかあるのかなー。できるだけintにするとかね。

で、新たな拡張作って、回避しました。

まあ、キャストするとかあるんですけど、折角Chaining Assertion使ってるのに、そんなの気持ちよくない。
今回は以下のような拡張メソッド作って回避しました。
拡張メソッドはより適合する方を選択してくれます。

publicstaticclass NumericAssertEx
{
    publicstaticvoid Is(thisbyte actual, int expected, string message = "")
    {
        Assert.IsTrue(byte.MinValue <= expected && expected <= byte.MaxValue);
        Assert.AreEqual(actual, (byte)expected, message);
    }

    publicstaticvoid Is(thisshort actual, int expected, string message = "")
    {
        Assert.IsTrue(short.MinValue <= expected && expected <= short.MaxValue);
        Assert.AreEqual(actual, (short)expected, message);
    }

    publicstaticvoid Is(thisushort actual, int expected, string message = "")
    {
        Assert.IsTrue(ushort.MinValue <= expected && expected <= ushort.MaxValue);
        Assert.AreEqual(actual, (ushort)expected, message);
    }

    publicstaticvoid Is(thisuint actual, int expected, string message = "")
    {
        Assert.IsTrue(0<= expected);
        Assert.AreEqual(actual, (uint)expected, message);
    }

    publicstaticvoid Is(thisulong actual, int expected, string message = "")
    {
        Assert.IsTrue(0<= expected);
        Assert.AreEqual(actual, (ulong)expected, message);
    }
}

Viewing all articles
Browse latest Browse all 104

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>