ラベル .NetFramework の投稿を表示しています。 すべての投稿を表示
ラベル .NetFramework の投稿を表示しています。 すべての投稿を表示

2017年11月21日火曜日

文字列比較の速度を比べてみる


検証内容

文字列の一致についてどれが一番早いかを比較。
調査する種類は、以下の3つとする


  • String.CompareTo
  • ==演算子
  • String.Compare




検証コード

static void StringCompare()
{
    var count = 100000;
    var ret = false;
    var inputStr1 = "aBcDeFgHiJkLmNoPqRsTuVwXyZ0123456789";
    var inputStr2 = "abCdEfGhIjKlMnOpQrStUvWxYz0123456789";
    Console.WriteLine("---------------------------------");
    Console.WriteLine($"ループ回数:{count:d}");

    //-----------------------------------------------------------------
    var time = Stopwatch.StartNew();
    for (var i = 0; i < count; i++)
    {
        ret = inputStr1.ToLower().CompareTo(inputStr2.ToLower()) ==0;
    }
    time.Stop();
    Console.WriteLine($"CompareTo : {time.ElapsedMilliseconds}ms");

    //-----------------------------------------------------------------
    time.Restart();
    for (var i = 0; i < count; i++)
    {
        ret = (inputStr1.ToLower() == inputStr2.ToLower());
    }
    time.Stop();
    Console.WriteLine($"== : {time.ElapsedMilliseconds}ms");

    //-----------------------------------------------------------------
    time.Restart();
    for (var i = 0; i < count; i++)
    {
        ret = String.Compare(inputStr1 ,inputStr2,true) == 0;
    }
    time.Stop();
    Console.WriteLine($"String.Compare : {time.ElapsedMilliseconds}ms");
}

結果

---------------------------------
ループ回数:100000
CompareTo : 108ms
== : 74ms
String.Compare : 104ms
---------------------------------
ループ回数:100000
CompareTo : 112ms
== : 61ms
String.Compare : 79ms
---------------------------------
ループ回数:100000
CompareTo : 88ms
== : 47ms
String.Compare : 77ms
---------------------------------
ループ回数:100000
CompareTo : 105ms
== : 61ms
String.Compare : 81ms
---------------------------------
ループ回数:100000
CompareTo : 103ms
== : 45ms
String.Compare : 99ms

結論

==演算子が速い!!
でも、10万回も回しての数十msなら、どちらでもよいかも。
っていうか、こちらについても相当シビアな環境じゃなきゃ影響なし。

2017年11月20日月曜日

C#で文字が含まれるかどうかの判定速度を比較してみた


検証内容

文字列の中から、1文字(char)が含まれるかどうかを調べる。
調査する種類は、以下の4つ


  • Contains("文字列")
  • Contains('文字')
  • IndexOf("文字列")
  • IndexOf('文字')


検証コード


static void TestContains()
{
    var count = 100000;
    var ret = false;
    var inputStr = "abcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefg";
    Console.WriteLine("---------------------------------");
    Console.WriteLine($"ループ回数:{count:d}");
    var time = Stopwatch.StartNew();
    for (var i = 0; i < count; i++)
    {
        ret = inputStr.Contains("g");
    }
    time.Stop();
    Console.WriteLine($"Contains(\"g\") : {time.ElapsedMilliseconds}ms");
    time.Restart();
    for (var i = 0; i < count; i++)
    {
        ret = inputStr.Contains('g');
    }
    time.Stop();
    Console.WriteLine($"Contains('g') : {time.ElapsedMilliseconds}ms");
    time.Restart();
    for (var i = 0; i < count; i++)
    {
        ret = inputStr.IndexOf("g") > 0;
    }
    time.Stop();
    Console.WriteLine($"IndexOf(\"g\") : {time.ElapsedMilliseconds}ms");
    time.Restart();
    for (var i = 0; i < count; i++)
    {
        ret = inputStr.IndexOf('g') > 0;
    }
    time.Stop();
    Console.WriteLine($"IndexOf('g') : {time.ElapsedMilliseconds}ms");
}

結果

ループ回数:100000
Contains("g") : 39ms
Contains('g') : 113ms
IndexOf("g") : 432ms
IndexOf('g') : 8ms
---------------------------------
ループ回数:100000
Contains("g") : 29ms
Contains('g') : 115ms
IndexOf("g") : 417ms
IndexOf('g') : 7ms
---------------------------------
ループ回数:100000
Contains("g") : 30ms
Contains('g') : 115ms
IndexOf("g") : 300ms
IndexOf('g') : 5ms
---------------------------------
ループ回数:100000
Contains("g") : 27ms
Contains('g') : 80ms
IndexOf("g") : 287ms
IndexOf('g') : 4ms
---------------------------------
ループ回数:100000
Contains("g") : 23ms
Contains('g') : 74ms
IndexOf("g") : 335ms
IndexOf('g') : 6ms

結論

1文字の検索なら、IndexOfが速い!!
でも、10万回も回しての数百msなら、どちらでもよいかも。
っていうか、Contains("文字列")でもそこそこ速いから、相当シビアな環境じゃなきゃ影響なし。

2017年11月19日日曜日

C#でStringBuilderと+= 演算子の速度比較をしてみた


概要

StringBuilderと+= 演算子の速度差が気になったので、実験してみました。
方法としては、以下のテストコードを5回繰り返し、結果を確認しています。

テストコード

static void TestAppendText()
{
    var count = 100000;
    Console.WriteLine("---------------------------------");
    Console.WriteLine($"ループ回数:{count:d}");
    var time = Stopwatch.StartNew();
    var message = string.Empty;
    var append = @"append";
    for (var i = 0; i < count; i++)
    {
        message += append;
    }
    time.Stop();
    Console.WriteLine($"String += : {time.ElapsedMilliseconds}ms");
    time.Restart();
    var builderMessage = new StringBuilder();
    for (int i = 0; i < count; i++)
    {
        builderMessage.Append(append);
    }
    time.Stop();
    Console.WriteLine($"StringBuilder: {time.ElapsedMilliseconds}ms");
}

結果

---------------------------------
ループ回数:100000
String += : 23382ms
StringBuilder: 1ms
---------------------------------
ループ回数:100000
String += : 22175ms
StringBuilder: 1ms
---------------------------------
ループ回数:100000
String += : 23060ms
StringBuilder: 1ms
---------------------------------
ループ回数:100000
String += : 23978ms
StringBuilder: 1ms
---------------------------------
ループ回数:100000
String += : 22435ms
StringBuilder: 2ms

結論

明らかに、StringBuilderを使用したほうが早いという結果になりました。
やっぱり、StringBuilderのほうが早くていいよね。+=はだめだね。っていう結論にしてもいいのですが、
試しにループ回数を100回にした場合には、以下の結果になっています。

---------------------------------
ループ回数:100
String += : 0ms
StringBuilder: 0ms

ms単位での差が分かりません。
なので100回程度の文字列の連結であれば、どちらも気にならないと思います。
そもそも、文字列を10万回も結合しなければいけないコードを書く人が悪いと思います。

結論としては、StringBuilderをお勧めはするけど、強要はしないって感じでしょうかねぇ。

2017年11月14日火曜日

C#で共用体(union)を利用する

C#で共用体(union)を利用する


「C#で共用体(union)を利用する」と書いたけれども、C#には、共用体がありません。
属性(StructLayoutとFieldOffset)を駆使して記載します。



[StructLayout(LayoutKind.Explicit)]struct BitData{
    [FieldOffset(0)]    public byte Data0;
    [FieldOffset(1)]    public byte Data1;
    [FieldOffset(2)]    public byte Data2;
    [FieldOffset(3)]    public byte Data3;
    [FieldOffset(0)]    public UInt32 Data;}



LayoutKind.Explicitを指定することで、
フィールド内のFieldOffsetが使用可能になります。



2017年11月10日金曜日

C#でTextBoxに数値のみの入力制限をする方法



C#でTextBoxに数値のみの入力制限をする方法を紹介します。
基本的な入力制限はもちろんのこと、コピペや再変換にも対応。

対応方法としては、テキスト変換時に数値以外を空文字に変更するだけ。
ただし、文字の削除のみだと、選択位置が変わるため、少し調整しています。


Regex m_NumOnlyRegex = new Regex("[^0-9]");
private void numTextBox_TextChanged( object sender, EventArgs e )
{
    var preTextLen = numTextBox.Text.Length;
    var selectPos = numTextBox.SelectionStart;
    numTextBox.Text = m_NumOnlyRegex.Replace( numTextBox.Text, String.Empty );
    var removeLen = preTextLen - numTextBox.Text.Length;
    if( selectPos > removeLen )
    {
        numTextBox.SelectionStart = selectPos - removeLen;
    }
    else
    {
        numTextBox.SelectionStart = 0;
    }
}

初期化したバイト配列の作成(C#)その2


初期化したバイト配列の別のやり方があったため、記載。
ついでに速度を比較してみました。

実装

配列を作った後に、値を設定しなおして配列に戻すw

var datas = new Double[10000].Select(val=> val = 5.0).ToArray();

もう一つの方法は、こちらを参照

速度比較のコード


private void Test()
{
    InitializeArray_Select();
    InitializeArray_Repeat();
}
private void InitializeArray_Select()
{
    var stopwatch = new System.Diagnostics.Stopwatch();
    stopwatch.Start();
    var datas = new Double[10000].Select(val=> val = 5.0).ToArray();
    stopwatch.Stop();
    Debug.WriteLine( stopwatch.ElapsedTicks );
}
private void InitializeArray_Repeat()
{
    var stopwatch = new System.Diagnostics.Stopwatch();
    stopwatch.Start();
    var datas = Enumerable.Repeat<Double>(5.0,10000).ToArray();
    stopwatch.Stop();
    Debug.WriteLine( stopwatch.ElapsedTicks );
}

比較結果


InitializeArray_Select :6954tick(6.9ms)
InitializeArray_Repeat:3367tick(3.4ms)

Enumerable.Repeatのほうが少しはやい。

2017年11月8日水曜日

C#でDecimalの演算速度が遅いので速度比較


C#でDecimalの演算速度が遅い気がしたので、計測してみた。
比較対象は、天下の浮動小数点のDouble。


計測の際に使用したプログラム

private void Test()
{
    DecimalDivide();
    DoubleDivide();
}
private void DecimalDivide()
{
    var stopwatch = new System.Diagnostics.Stopwatch();
    stopwatch.Start();
    Decimal val = 10000;
    Decimal calc= 2m;
    for( Int32 i = 0; i < 10000; i++ )
    {
        val = val / calc;
    }
    stopwatch.Stop();
    Debug.WriteLine( stopwatch.ElapsedTicks );
}
private void DoubleDivide()
{
    var stopwatch = new System.Diagnostics.Stopwatch();
    stopwatch.Start();
    Double val = 10000;
    Double calc = 2.0;
    for( Int32 i = 0; i < 10000; i++ )
    {
        val = val / calc;
    }
    stopwatch.Stop();
    Debug.WriteLine( stopwatch.ElapsedTicks );
}

測定結果

速度差にして約5倍。計算が多くなってくると、ちょっと気になる差かも。。。
まぁ、基本的に、使用する型は、必要十分な型にすべきということですね。

Decimal:1309tick(1.3ms)
Double:224tick(0.24ms)

2017年7月4日火曜日

C#でのBitmapクラスへのデータの設定方法

Bitmapクラスへのデータの設定方法

入力データが、TopDownでもBottomUpでも、変換可能な関数を作成したので、メモ。

void CopyBitmapData( Byte[] pixelData, Boolean isTopDown,Int32 bitCount, Bitmap bmp )
{
    BitmapData bmpData = bmp.LockBits(
                new Rectangle(0, 0, bmp.Width, bmp.Height),
                ImageLockMode.ReadWrite,
                bmp.PixelFormat);

    var stride = (bmp.Width * bitCount + 31) / 32*4;

    int pos = bmpData.Scan0.ToInt32();
    Parallel.For( 0, bmp.Height, ( hpos ) =>
    {
        var destPtr = IntPtr.Zero;
        if( isTopDown )
        {
            destPtr = new IntPtr( pos + hpos * stride );
        }
        else
        {
            destPtr = new IntPtr( pos + ( bmp.Height - hpos - 1 ) * stride );
        }
        Marshal.Copy( pixelData, hpos * stride, destPtr, stride );
    } );
    bmp.UnlockBits( bmpData );
}

2017年7月3日月曜日

Bitmapのデータ構造(Strideの計算)

Bitmapの4Byteのアライメント

Bitmapの4Byteのアライメントの簡単な計算方法をメモ。

var stride = (width * bitcount + 31)/32*4;

補足


4Byteのアライメントを計算する際に、Byte単位で計算すると、次の通り。

var lineSize = width * bitcount/4;
lineSize = (lineSize +3)  / 4 *4;

これをbit単位で計算すると、

var stride = (width * bitcount + 31)/32*32;

となり、Byteに変換すると、
var stride = (width * bitcount + 31)/32*32 / 8;
なので、
var stride = (width * bitcount + 31)/32*4;

で計算可能になる。 

2016年9月28日水曜日

C#での四捨五入での落とし穴

C#で四捨五入をする際に、2つの落とし穴があります。
それは、四捨五入に失敗する問題と、もう一つは速度の問題です。


四捨五入に失敗

こうやると、四捨五入に失敗します。

Math.Round( 0.5  );

それは、Math.Roundは、デフォルトでは、「2 つの整数 (一方が偶数で、もう一方が奇数) の中間にある場合は、偶数が返されます。」からです。
そのため、上の関数を実行すると、0が返ります。
通常の四捨五入をするためには、引数の

MidpointRounding.AwayFromZero

を追加する必要があります。


四捨五入の速度

プログラムを書くときには、標準的な関数がある場合には、そちらを使ったほうが良いです。
でも、そうとも言えない場合もあります。
今回、四捨五入をするにあたり、[Math.Round]と、[0.5を加算後にInt32でキャスト]した場合の速度を比較しました。


static void Main( string[] args )
{
    var count = 10000;
    var val = new Decimal(0.5d);
    var st = new Stopwatch();
    st.Start();
    for( var i = 0; i < count; i++ )
    {
        Console.WriteLine( Math.Round( val + i, MidpointRounding.AwayFromZero ) );
    }
    st.Stop();
    var time1 = st.ElapsedMilliseconds;
    st.Reset();
    var add = new Decimal(0.5);
    st.Start();
    for( var i = 0; i < count; i++ )
    {
        Console.WriteLine( (Int32)(val + i + add) );
    }
    st.Stop();
    var time2 = st.ElapsedMilliseconds;
    Console.WriteLine();
    Console.WriteLine( time1 );
    Console.WriteLine( time2 );
}

結果は次の通りです。

5286
452
予想はしていましたが、少し驚きました。
繰り返し処理でなければ、あまり考慮する必要はないかもしれませんが、
繰り返し四捨五入する場合には、Int32でキャストしたほうが良いと思います。


2016年9月24日土曜日

C#でのboolのサイズについて(Managed、UnManaged、Marshal)

Windowsでのboolって、昔からいろいろと厄介なことがあります。(サイズ間違えたり、サイズ間違えたり・・・)
というわけで、少しまとめてみました。

結論から書くと、C++からC#へのデータの受け渡し時には
bool:「MarshalAs( UnmanagedType.U1)」
BOOL:「MarshalAs( UnmanagedType.Bool)」

ってことを言いたいだけです。

VisualC++(UnManaged)


VisualC++の時代から、BOOLとboolで違いがあることは、皆さんよくご存じだと思います。

bool:1byte
BOOL:4byte

この理由自体は、単純で、"minwindef.h"を見れば、すぐわかると思います。

typedef int                 BOOL;

BOOL自体は、intなので、4バイトになります。


C#(Managed)


C#になって、違いがなくなりました。

bool:1byte
System.Boolean:1byte


Marshal


では、C++とC#でデータのやり取りをする場合は、どうなってしまうのか。

Marshal.SizeOfで、サイズを確認してみたいと思います。



Marshal.SizeOf(bool):4byte
Marshal.SizeOf(Boolean):4byte

結果は「4バイト」です。そのため、dllimportした場合や、PtrToStructureなど、C++からC#にデータをコピーする場合には、注意が必要になります。
C++の構造体で、boolを使用している場合には、意図的に、「1バイトだよ」と教えてあげる必要があります。(Marshal時には、デフォルトで、「UnManagedType.Bool」がデフォルトとなっています。)
そのために意図的に「MarshalAs( UnmanagedType.U1)」を指定する必要があります。

以下の構造体の例を見てます。

[StructLayout(LayoutKind.Sequential,Pack =1)]
struct boolStruct
{
    bool value;
}
[StructLayout( LayoutKind.Sequential, Pack = 1 )]
struct boolStructU1
{
    [MarshalAs( UnmanagedType.U1)]
    bool value;
}
class Program
{
    static void Main( string[] args )
    {
        Console.WriteLine( "boolStruct:{0}byte",
            Marshal.SizeOf( typeof(boolStruct) ) );
        Console.WriteLine( "boolStructU1:{0}byte",
            Marshal.SizeOf( typeof( boolStructU1 ) ) );
    }
}

結果:
boolStruct:4byte
boolStructU1:1byte
皆様、C++とのデータのやり取りでboolを使用する場合にはお気を付けください。

参照:

2016年9月11日日曜日

GUIでの非同期処理(async/await)

先に今日の内容をまとめておきます。

非同期処理のAsync/Awaitは便利です。


では、前ふりです。

GUIでの非同期処理って、いろいろと面倒なイメージがありませんか。
非同期処理を行う場合って、脳内ではこんなこと考えていませんでしたか?

ボタンを押す→処理が重たい→スレッドにする→最終結果を表示したいから、スレッド終了待ち→待ってるとGUI固まる→DoEventでごまかす。

結局、スレッドにする、しないにかかわらず、クリック後の処理で待ちたいけれど、固まったように見えないようにしなければ!ってことを考えていたのではないでしょうか。

まずは、今まで書いていたようなコードを見てみましょう。

        private async void button1_Click( object sender, EventArgs e )
        {
            var msg = HeavyCalcurate_Thread();
            MessageBox.Show( msg );
        }

        // Asnc,Awaitがないころのコード(スレッドで回避)
        // 処理中でも、GUIを操作可能
        private String HeavyCalcurate_Thread()
        {
            var task = new TaskFactory().StartNew( ()=>
            {
                for( var i = 0; i < 10; i++ )
                {
                    System.Threading.Thread.Sleep( 2000 );
                }

            } );
            // 終了待ち
            var wait = false;
            while( wait == false )
            {
                wait = task.Wait( 100 );
                Application.DoEvents();//<---がんばって処理を逃がすw
            }
            return "完了";
        }


要は、スレッドの処理待ちです。スレッドが終わった後に、メッセージボックスを出したい。画面は、操作したい。って場合です。
では、C#5 で追加されたasync/awaitを使って書いてます。

private async void button1_Click( object sender, EventArgs e )
{
    var msg = await HeavyCalcurate_Async();
    MessageBox.Show( msg );
}
private async Task<String> HeavyCalcurate_Async()
{
    var task = await new TaskFactory().StartNew( ()=>
    {
        for( var i = 0; i < 10; i++ )
        {
            System.Threading.Thread.Sleep( 2000 );
        }
        return "完了";
    } );
    return task;
}

コードが簡単になっていますね。
上に書いた処理待ちのコードが、だいぶすっきりしています。
このように書くだけで、Taskが実行され、そのあとにちゃんとメッセージボックスが出ます。
さらに、一番大事なのは、処理待ちの間も問題なくGUIを動かしたりできます。

ってわけで、1つ賢くなったのですが、一つ残念なことがありました。
C# 5が当たり前な世代では、async/awaitがない場合にはなんて考えないかも?!
使うのが当たり前でしょって思ったそこのあなた!
どうか、筆者を年寄り扱いしないでくださいね。そこのところ、よろしくお願いいたします。

おまけ


コンパイラによるラムダ式の展開に絡みますが、上記コードをコンパイルしたコードを見てみると、
DebugとReleaseでだいぶコードが異なるので面白いかも。

コンパイラによるラムダ式の展開

ラムダ式で、ラムダ式外部の変数を使っているか、いないかによって処理が少し最適化されているようです。


var val =10;var func = new Func<int32>(()=>;val);

コードを見てみると、上記のような場合には、そのままの形になっています。

var func = new Func<int32>(()=>; { int a = 10; return a*a; } );

このような形でラムダ式の外側の変数を使用しない場合には、
ラムダ式用のinnnerクラスを持ち、static関数を呼び出す形に最適化されているようです。
[Serializable]private sealed class innerclass{    public static readonly Program.innerclass inclass = new Program.innerclass();
    public static Func<int> func;
    internal int method()    {        return 1;    }}

private static void Main( string[] args ){    if( Program.innerclass.func == null )    {        Program.innerclass.func = new Func<int>(            Program.innerclass.inclass.method );    }}
基本的に、外部の変数を使用していない場合のみなので、
スレッドには影響しません。

以上です。だからどうしたといわれそうですが、それだけです。

2016年9月9日金曜日

C#で動的プラグインの作成(InterFace未使用版)

C#で動的プラグインを作るといえば、通常は、インターフェースを作り、インターフェース派生のプラグインを作って呼び出すのが普通だと思います。(そのうち書いてみます)

今日は、プラグイン側にもっと自由を与えてみたいと思います。
プラグインには、あの大空に翼を広げ飛んで行ってもらいます。(でも見えるところにいてくれないと困るけど)

呼び出すクラスと、呼び出す関数は、アプリケーション側では制御せず、プラグインを作成するタイミングで自由に決めることができます。

使った機能
  • カスタム属性
  • Activator
  • Invoke

構成としては、
  • アプリケーション(exe本体)
  • プラグイン識別用の属性定義(DLL)
  • プラグイン(DLL)

の3部作です。アプリケーションとプラグインは、属性定義(DLL)を参照しています。



では、さっそくサンプルコードです。

アプリケーション(exe)の実装

アプリケーション本体としては、次のような処理をしているだけです。
  1. 任意のフォルダーからdllを検索
  2. アセンブリ属性の確認(期待する属性の定義があれば、プラグインとみなす)
  3. タイプの取得(期待する属性の定義があれば、プラグインクラスとみなす)
  4. メソッドを呼び出す。

プラグイン用属性定義(DLL) 

属性定義では、次の2つのカスタム属性を定義しています。
  • アセンブリ用のカスタム属性
  • クラス用のカスタム属性
※クラス用のカスタム属性では、呼び出すクラスの順番、クラス内で呼び出す関数の順番を
指定できるようにしています。



プラグイン(DLL)

プラグインでは、アセンブリのカスタム属性と、各クラスで、クラスのカスタム属性を記載しています。
テストのために、属性の定義をしていないクラス(Sample3)も記載しています。



実行結果

実行結果は次のようになり、大成功でした。


Called Sample2
Called SampleA
Called SampleB


通常であれば、
ここまで、プラグインに自由を与えることはないと思います。
動的プラグインを作る際には、程よく使用していただければと思います。
(プラグインかどうかの判断で、アセンブリのカスタム属性くらいなら使うかも)



2016年9月7日水曜日

C#7.0の新機能:is演算子(今までとは一味違う)

VisualStudio15で追加される予定のC#7.0 をVisualStudio15 Preview4で確認してみました。

今までのis演算子の使用方法が増えるみたいです。

今までは、インスタンスがObjectクラスで渡っていた時など、as でキャストして、nullチェックしていました。
それが、isを使うことにより、キャスト+nullチェックができるようになるみたいです。



Object obj = new SampleClass();
if (obj is SampleClass sample)
{
    Console.WriteLine($"{sample.Message}");
}




C# 7のコードを展開するとこうなる



Object obj = new SampleClass();
var sample = obj as SampleClass;
Boolean isNotNull = (sample != null);
if (isNotNull)
{
    Console.WriteLine("{0}", sample.Message);
}

補足

内部的には、is 演算子の後ろのTypeでas演算子を使ってキャストするため、
もちろん、ベースクラスにキャストもできます。

public class SampleBaseClass
{
    public String Message { get; set; } = "message";
}

public class SampleClass : SampleBaseClass
{
}

class Program
{
    static void Main()
    {
        Object obj = new SampleClass();
        if( obj is SampleBaseClass sample)
        {
            Console.WriteLine( $"{sample.Message}" );
        }
    }
}

C#6.0の新機能:メソッド本体にラムダ式

関数のラムダ式


VisualStudio2015で追加されたのC#6.0 で関数のラムダ式を試してみました。


public Int32 Add(Int32 val1, Int32 val2) => val1 * val2;


この使い道が想像できていません。関数をラムダ式で書く理由って何でしょうか?

ちなみに私は、ラムダ式を書くのに波括弧を使う癖があるのですが、
関数のラムダ式に入れたら、コンパイラ様に怒られました。

public Int32 Add2(Int32 val1, Int32 val2) => { return val1* val2; }
Error CS1519 クラス、構造体、またはインターフェイス メンバーの宣言でトークン '{' が無効です。





関数がラムダ式なら、Funcに入れられるかと思い、入れてみました。
ついでに、普通の関数もFuncに入れてみました。


public Int32 Add(Int32 val1, Int32 val2) => val1 * val2;
public Int32 Add2(Int32 val1, Int32 val2) { return val1 * val2; }

void SampleMethod()
{
    Func<Int32, Int32, Int32> func = Add;
    Func<Int32, Int32, Int32> func2 = Add2;
}


な、なんと、どちらも普通に動きます。
さぁ、やっぱり、使い道が分からなくなってきました。
誰か、使い方教えてけれ!!!!!!!!!!!!!!


2016年9月6日火曜日

C#7.0の新機能:ローカル関数(関数内の関数)

VisualStudio15で追加される予定のC#7.0 をVisualStudio15 Preview4で確認してみました。

C#7.0 では、関数内に関数を記入できるようになるようです。

ちなみに、関数内の関数内にも関数が書けるようです。<---わかりにくい。。。
あと、関数なので当たり前かもしれませんが、CallerFilePathの属性なんかも使えます。
まぁ、その場合は、呼び出し元なので、「WriteLine」関数を指し示します。

using System;
using System.Runtime.CompilerServices;
namespace ConsoleApp1v15
{
    class Sample
    {
        static void Main()
        {
            void Method()
            {
                void WriteLine(string message,
                        [CallerFilePath] string file = "",
                        [CallerLineNumber] int line = 0,
                        [CallerMemberName] string member = "")
                {
                    var s = string.Format("{0}:{1} - {2}: {3}", file, line, member, message);
                    Console.WriteLine(s);
                }
                WriteLine("message");
            }
            Method();
        }
    }
}


結果

c:\Projects\ConsoleApp1v15\ConsoleApp1v15\Program.cs:19 - Method: message

C#7.0の新機能:桁区切り記号(数字セパレータ)


VisualStudio15で追加される予定のC#7.0 をVisualStudio15 Preview4で確認してみました。

C#7.0 では、数値に桁区切り記号を追加して、記載できるようになるみたいです。


Int32 val1 = 1_010_010;
Console.WriteLine($"{val1}");


では、どこまで対応しているか、試してみたいと思います。

ノーマル

Int32 val1 = 10_101_010;
Console.WriteLine($"{val1}");

3桁以外の区切り位置

Int32 val2 = 10_1010_10;
Console.WriteLine($"{val2}");

区切り文字いっぱい

Int32 val3 = 10_101___010;
Console.WriteLine($"{val3}");

16進数で区切り文字

Int32 val4 = 0x9a21_12;
Console.WriteLine($"{val4}");

2進数で区切り文字

Int32 val5 = 0b100_110_100_010_000_100_010_010;
Console.WriteLine($"{val5}");


小数点で区切り文字

double val6 = 0.12_34;
Console.WriteLine($"{val6}");

ここまでは大丈夫でした。
10101010
10101010
10101010
10101010
10101010
0.1234


ここからは、コンパイラで怒られてしまった例:

バイナリリテラルのbの直後

Int32 val7 = 0b_100_110_100_010_000_100_010_010;
Console.WriteLine($"{val7}");

数値の最初または最後

Int32 val8 = 123_;
Int32 val9 = _123;
Console.WriteLine($"{val8}");
Console.WriteLine($"{val9}");

考察

とりあえず、すぐに思いつく限りはやってみました。
基本的な箇所には、使えるようです。(当たり前ですが・・・)

これで、桁数が大きい場合のコードミスが減りそうですね。
(でも、コードミスするような人は、使ってくれないんですよね(T_T))


2016年9月4日日曜日

C#7.0の新機能:文字列の書式(String.Format)


文字列の書式(String.Format)に変数を直接記入


VisualStudio15で追加される予定のC#7.0 をVisualStudio15 Preview4で確認してみました。

C#7.0 では、文字列の書式(String.Format)に変数を直接記入できるようになるようです。
今までは、{0},{1},{2}のようにして記載していましたが、その部分に直接変数名が入れられます。
記載するには、$マークが必須です。

var val1 = 1;
var val2 = 0x02;
var val3 = 0b011;
Console.WriteLine("{0},{1},{2}",val1,val2,val3);
Console.WriteLine($"{val1},{val2},{val3}");

結果
1,2,3
1,2,3

C#7.0の新機能:2進数

VisualStudio15で追加される予定のC#7.0 をVisualStudio15 Preview4で確認してみました。

C#7.0 では、数値を2進数で、記載できるようになるみたいです。


//数値
var val1 = 1;
var val2 = 0x02;
var val3 = 0b011;
Console.WriteLine("{0},{1},{2}", val1, val2, val3);

これを今までの VisualStudio2015 で記載すると、こんな風に叱られます。

エラー CS0103 現在のコンテキストに 'b011' という名前は存在しません。

これをVisualStudio15Preview版で試してみると問題なくビルドが通ります。
結果は次のようになります。というか、そのままです。

1,2,3

余り2進数として値を見たいことは少ないかもしれませんが、
EnumにFlagsAttributeをつけて利用することはあるかもしれないです。

    [FlagsAttribute]
    public enum Sports
    {
        BaseBall   = 0b0001,
        FootBall   = 0b0010,
        Basketball = 0b0100,
    }
    class Sample
    {
        static void Main()
        {
            var sports = Sports.BaseBall | Sports.Basketball;
            Console.WriteLine("{0}", sports);
        }
    }

結果

BaseBall, Basketball,

無事に、Enum値がカンマ区切りで表示されました。めでたしめでたし。