2011-12-27T23:38:21の更新内容

programming/tips/calc_digits/index.wiki.txt

current previous
1,362 0,0
+
${smdncms:title,数の桁数を求める}
+
${smdncms:keywords,VB.NET,C#,桁数,Math.Log10}
+
${smdncms:tags,api/.net,lang/vb,lang/c#}
+
${smdncms:document_versions,codelang=cs,codelang=vb}
+

          
+
正の10進整数の桁数を求める方法のいくつか。 負数は考えない。
+

          
+
-関連するページ
+
--[[programming/netfx/mathematics/0_math]]
+
--[[programming/netfx/string/3_formatting]]
+

          
+
#googleadunit
+

          
+
*対数(log&sub{10};)を取る
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    foreach (var num in new[] {0, 1, 9, 10, 11, 99, 100, 500, 999, 1000, 6789, 10000, 99999}) {
+
      Console.WriteLine("{0} => {1}", num, unchecked((int)Math.Log10(num)) + 1);
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+

          
+
Class Sample
+
  Shared Sub Main()
+
    For Each num As Integer In New Integer() {0, 1, 9, 10, 11, 99, 100, 500, 999, 1000, 6789, 10000, 99999}
+
      If num = 0 Then
+
        Console.WriteLine("{0} => 1", num)
+
      Else
+
        Console.WriteLine("{0} => {1}", num, CInt(Math.Floor(Math.Log10(num))) + 1)
+
      End If
+
    Next
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
0 => -2147483647
+
1 => 1
+
9 => 1
+
10 => 2
+
11 => 2
+
99 => 2
+
100 => 3
+
500 => 3
+
999 => 3
+
1000 => 4
+
6789 => 4
+
10000 => 5
+
99999 => 5
+
}}
+

          
+
&msdn(netfx,member,System.Math.Log10){Math.Log10};は値が0の場合NegativeInfinityを返すので、個別に処理する必要がある。
+

          
+
*文字列にして長さを求める
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    foreach (var num in new[] {0, 1, 9, 10, 11, 99, 100, 500, 999, 1000, 6789, 10000, 99999}) {
+
      Console.WriteLine("{0} => {1}", num, num.ToString("D").Length);
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+

          
+
Class Sample
+
  Shared Sub Main()
+
    For Each num As Integer In New Integer() {0, 1, 9, 10, 11, 99, 100, 500, 999, 1000, 6789, 10000, 99999}
+
      Console.WriteLine("{0} => {1}", num, num.ToString("D").Length)
+
    Next
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
0 => 1
+
1 => 1
+
9 => 1
+
10 => 2
+
11 => 2
+
99 => 2
+
100 => 3
+
500 => 3
+
999 => 3
+
1000 => 4
+
6789 => 4
+
10000 => 5
+
99999 => 5
+
}}
+

          
+
*10で割り続けた回数から求める
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    foreach (var num in new[] {0, 1, 9, 10, 11, 99, 100, 500, 999, 1000, 6789, 10000, 99999}) {
+
      var digit = 1;
+

          
+
      for (var n = num; 10 <= n; digit++) {
+
        n /= 10;
+
      }
+

          
+
      Console.WriteLine("{0} => {1}", num, digit);
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+

          
+
Class Sample
+
  Shared Sub Main()
+
    For Each num As Integer In New Integer() {0, 1, 9, 10, 11, 99, 100, 500, 999, 1000, 6789, 10000, 99999}
+
      Dim digit As Integer = 1
+
      Dim n As Integer = num
+

          
+
      While 10 <= n
+
        digit += 1
+
        n \= 10
+
      End While
+

          
+
      Console.WriteLine("{0} => {1}", num, digit)
+
    Next
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
0 => 1
+
1 => 1
+
9 => 1
+
10 => 2
+
11 => 2
+
99 => 2
+
100 => 3
+
500 => 3
+
999 => 3
+
1000 => 4
+
6789 => 4
+
10000 => 5
+
99999 => 5
+
}}
+

          
+
*桁数のテーブルと比較する
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+

          
+
class Sample {
+
  static readonly int[] digits = {0, 9, 99, 999, 9999, 99999, 999999, /*9999999, 99999999, ... */};
+

          
+
  static void Main()
+
  {
+
    foreach (var num in new[] {0, 1, 9, 10, 11, 99, 100, 500, 999, 1000, 6789, 10000, 99999}) {
+
      var digit = 1;
+

          
+
      for (;;digit++) {
+
        if (num <= digits[digit])
+
          break;
+
      }
+

          
+
      Console.WriteLine("{0} => {1}", num, digit);
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+

          
+
Class Sample
+
  Shared ReadOnly digits As Integer() = {0, 9, 99, 999, 9999, 99999, 999999} ' , 9999999, 99999999, ... }
+

          
+
  Shared Sub Main()
+
    For Each num As Integer In New Integer() {0, 1, 9, 10, 11, 99, 100, 500, 999, 1000, 6789, 10000, 99999}
+
      Dim digit As Integer = 1
+

          
+
      While digits(digit) < num
+
        digit += 1
+
      End While
+

          
+
      Console.WriteLine("{0} => {1}", num, digit)
+
    Next
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
0 => 1
+
1 => 1
+
9 => 1
+
10 => 2
+
11 => 2
+
99 => 2
+
100 => 3
+
500 => 3
+
999 => 3
+
1000 => 4
+
6789 => 4
+
10000 => 5
+
99999 => 5
+
}}
+

          
+
*速度比較
+
ランダムな数10,000,000個について上記の方法で桁数を求めた場合の速度を比較したもの。 それぞれ3回ずつ試行。 Ubuntu 11.10 + Mono 2.10.8での実行結果。
+

          
+
-結果
+
--最速はテーブルを使った方法、最も遅いのは文字列化
+
--10で割るよりはMath.Log10を使った方が早い
+
--ただし、数がある程度小さい場合は、Math.Log10より10で割る方が速くなる
+
--Math.Log10の速度は数の大きさによらず一定
+

          
+
#prompt(数の範囲が1 ~ int.MaxValueの場合){{
+
4.0.30319.1
+
Unix 3.0.0.14
+
1 ~ 2147483647
+

          
+
Math.Log10    : 00:00:01.1368336
+
String.Length : 00:00:04.1699058
+
divide by 10  : 00:00:01.7512138
+
table         : 00:00:00.7284158
+

          
+
Math.Log10    : 00:00:01.1065396
+
String.Length : 00:00:04.1047607
+
divide by 10  : 00:00:01.7776515
+
table         : 00:00:00.7468283
+

          
+
Math.Log10    : 00:00:01.1293331
+
String.Length : 00:00:04.1484966
+
divide by 10  : 00:00:01.7761593
+
table         : 00:00:00.7391820
+
}}
+

          
+
#prompt(数の範囲が1 ~ 10000の場合){{
+
4.0.30319.1
+
Unix 3.0.0.14
+
1 ~ 10000
+

          
+
Math.Log10    : 00:00:01.1085428
+
String.Length : 00:00:02.9993363
+
divide by 10  : 00:00:00.7884117
+
table         : 00:00:00.5584225
+

          
+
Math.Log10    : 00:00:01.1094404
+
String.Length : 00:00:02.9639001
+
divide by 10  : 00:00:00.7818080
+
table         : 00:00:00.5582405
+

          
+
Math.Log10    : 00:00:01.1111837
+
String.Length : 00:00:02.9534707
+
divide by 10  : 00:00:00.8002473
+
table         : 00:00:00.5687480
+
}}
+

          
+
#code(cs,検証に使ったコード){{
+
using System;
+
using System.Collections.Generic;
+
using System.Linq;
+
using System.Diagnostics;
+

          
+
class Sample {
+
  static readonly int[] digits = {0, 9, 99, 999, 9999, 99999, 999999, 9999999, 99999999, 999999999, int.MaxValue};
+

          
+
  const int min = 1;
+
  const int max = int.MaxValue;
+

          
+
  static IEnumerable<int> CreateSource(int seed, int count)
+
  {
+
    var rand = new Random(seed);
+

          
+
    for (; 0 < count; count--) {
+
      yield return rand.Next(min, max);
+
    }
+
  }
+

          
+
  static void Main()
+
  {
+
    Console.WriteLine(Environment.Version);
+
    Console.WriteLine(Environment.OSVersion);
+
    Console.WriteLine("{0} ~ {1}", min, max);
+
    Console.WriteLine();
+

          
+
    const int count = 10 * 1000 * 1000;
+
    int digit = 0;
+

          
+
    for (var i = 0; i < 3; i++) {
+
      var seed = unchecked((int)Environment.TickCount);
+

          
+
      var sw1 = Stopwatch.StartNew();
+

          
+
      foreach (var num in CreateSource(seed, count)) {
+
        digit = (int)Math.Log10(num) + 1;
+
      }
+

          
+
      sw1.Stop();
+

          
+
      Console.WriteLine("Math.Log10    : {0}", sw1.Elapsed);
+

          
+
      var sw2 = Stopwatch.StartNew();
+

          
+
      foreach (var num in CreateSource(seed, count)) {
+
        digit = num.ToString("D").Length;
+
      }
+

          
+
      sw2.Stop();
+

          
+
      Console.WriteLine("String.Length : {0}", sw2.Elapsed);
+

          
+
      var sw3 = Stopwatch.StartNew();
+

          
+
      foreach (var num in CreateSource(seed, count)) {
+
        digit = 1;
+
        for (var n = num; 10 <= n; digit++) {
+
          n /= 10;
+
        }
+
      }
+

          
+
      sw3.Stop();
+

          
+
      Console.WriteLine("divide by 10  : {0}", sw3.Elapsed);
+

          
+
      var sw4 = Stopwatch.StartNew();
+

          
+
      foreach (var num in CreateSource(seed, count)) {
+
        digit = 1;
+
        for (;;digit++) {
+
          if (num <= digits[digit])
+
            break;
+
        }
+
      }
+

          
+
      sw4.Stop();
+

          
+
      Console.WriteLine("table         : {0}", sw4.Elapsed);
+
      Console.WriteLine();
+
   }
+
  }
+
}
+
}}

programming/netfx/conversion/0_basetype/index.wiki.txt

current previous
465,72 465,6
 
42-30
42-30
 
}}
}}
 

        

        
+
ただし、BitConverter.ToStringの逆の動作をするメソッド、つまりBitConverter.ToStringの出力形式と同じ文字列からバイト配列を取得するメソッドは存在しないため、自分で実装する必要があります。 また、この形式の文字列から基本型に直接変換するメソッドも用意されていないため、これも自分で実装する必要があります。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+

          
+
class Sample {
+
  static byte[] ToByteArray(string data)
+
  {
+
    // ハイフン '-' で分割
+
    string[] byteStrings = data.Split('-');
+

          
+
    // 配列に分割した文字列をバイト配列に変換
+
    return Array.ConvertAll(byteStrings, delegate(string s) {
+
      return Convert.ToByte(s, 16); // 16進形式の文字列からByteに変換
+
    });
+
  }
+

          
+
  static void Main()
+
  {
+
    string data = "FF-FF-80-00";
+

          
+
    Console.WriteLine("{0} => {1} 0x{1:X8}", data, BitConverter.ToInt32(ToByteArray(data), 0));
+

          
+
    data = "00-00-00-00-00-6A-F8-40";
+

          
+
    Console.WriteLine("{0} => {1}", data, BitConverter.ToDouble(ToByteArray(data), 0));
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+

          
+
Class Sample
+
  Shared Function ToByteArray(ByVal data As String) As Byte()
+
    ' ハイフン '-' で分割
+
    Dim byteStrings As String() = data.Split("-"c)
+

          
+
    ' 配列に分割した文字列をバイト配列に変換
+
    Return Array.ConvertAll(Of String, Byte)(byteStrings, AddressOf ToByteFromHex)
+
  End Function
+

          
+
  Shared Function ToByteFromHex(ByVal hex As String) As Byte
+
    ' 16進形式の文字列からByteに変換
+
    Return Convert.ToByte(hex, 16)
+
  End Function
+

          
+
  Shared Sub Main()
+
    Dim data As String = "FF-FF-80-00"
+

          
+
    Console.WriteLine("{0} => {1} 0x{1:X8}", data, BitConverter.ToInt32(ToByteArray(data), 0))
+

          
+
    data = "00-00-00-00-00-6A-F8-40"
+

          
+
    Console.WriteLine("{0} => {1}", data, BitConverter.ToDouble(ToByteArray(data), 0))
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
FF-FF-80-00 => 8454143 0x0080FFFF
+
00-00-00-00-00-6A-F8-40 => 100000
+
}}
+

          
 
リファレンスでは明記されていませんが、結果として得られるバイト表現や変換結果は実行している環境のエンディアンなどにより変わると思われます。 現在実行している環境のエンディアンを調べるには、&msdn(netfx,member,System.BitConverter.IsLittleEndian){BitConverter.IsLittleEndianプロパティ};を参照します。 また、&msdn(netfx,type,System.Net.IPAddress){IPAddressクラス};の&msdn(netfx,member,System.Net.IPAddress.NetworkToHostOrder){NetworkToHostOrderメソッド};を使うことで整数型の値をネットワークバイトオーダー(ビッグエンディアン)からホストバイトオーダーに、&msdn(netfx,member,System.Net.IPAddress.HostToNetworkOrder){HostToNetworkOrderメソッド};を使うことでホストバイトオーダーからネットワークバイトオーダーに変換することが出来ます。
リファレンスでは明記されていませんが、結果として得られるバイト表現や変換結果は実行している環境のエンディアンなどにより変わると思われます。 現在実行している環境のエンディアンを調べるには、&msdn(netfx,member,System.BitConverter.IsLittleEndian){BitConverter.IsLittleEndianプロパティ};を参照します。 また、&msdn(netfx,type,System.Net.IPAddress){IPAddressクラス};の&msdn(netfx,member,System.Net.IPAddress.NetworkToHostOrder){NetworkToHostOrderメソッド};を使うことで整数型の値をネットワークバイトオーダー(ビッグエンディアン)からホストバイトオーダーに、&msdn(netfx,member,System.Net.IPAddress.HostToNetworkOrder){HostToNetworkOrderメソッド};を使うことでホストバイトオーダーからネットワークバイトオーダーに変換することが出来ます。
 

        

        
 
#tabpage(C#)
#tabpage(C#)

programming/netfx/sorting/0_basictypes/index.wiki.txt

current previous
1378,28 1378,33
 

        

        
 

        

        
 
*シャッフル
*シャッフル
~
ここまでは規則性のある順序でのソートを行ってきましたが、この順序をランダムにすることで配列やListをシャッフルすることが出来ます。 OrderByメソッドの場合、与えられたキーに基づいて並べ替えが行われますが、このキーにランダムな値を与えることでコレクションをシャッフルすることが出来ます。 次の例ではOrderByメソッドを使ってListをシャッフルしています。
ここまでは規則性のある大小関係に基づいたソートを行ってきましたが、この規則をランダムにすることで配列やListをシャッフルすることも出来ます。 次の例では、Array.Sortメソッドに毎回異なる結果を返す&msdn(netfx,type,System.Collections.Generic.IComparer`1){IComparer<T>};を指定することで配列をシャッフルしています。 IComparer<T>は、Comparision<T>デリゲートと同様の大小関係を定義するメソッドをクラスに実装するためのインターフェイスです。 IComparer<T>については[[programming/netfx/comparison/0_comparison]]で詳しく解説しています。
 

        

        
 
#tabpage(C#)
#tabpage(C#)
 
#code(cs){{
#code(cs){{
 
using System;
using System;
 
using System.Collections.Generic;
using System.Collections.Generic;
+
using System.Linq;
 

        

        
 
class Sample {
class Sample {
~
  static Random rand = new Random();
  // ランダムに並べ替えるためのIComparer<int>を実装するクラス
-
  class RandomComparer : IComparer<int> {
-
    public int Compare(int x, int y)
-
    {
-
      // -1, 0, +1いずれかの値をランダムに返す
-
      return rand.Next(-1, 2);
-
    }
 

        

        
~
  static int RandomKeySelector(int val)
    private Random rand = new Random();
+
  {
+
    // valに関係なく、ランダムなキーを返す
+
    return rand.Next();
 
  }
  }
 

        

        
 
  static void Main()
  static void Main()
 
  {
  {
~
    List<int> list = new List<int>(new int[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9});
    int[] arr = new int[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
-

          
-
    // シャッフル
-
    Array.Sort(arr, new RandomComparer());
 

        

        
~
    foreach (int val in list.OrderBy(RandomKeySelector)) {
    foreach (int val in arr) {
 
      Console.Write("{0}, ", val);
      Console.Write("{0}, ", val);
 
    }
    }
 
    Console.WriteLine();
    Console.WriteLine();
1410,21 1415,27
 
#code(vb){{
#code(vb){{
 
Imports System
Imports System
 
Imports System.Collections.Generic
Imports System.Collections.Generic
+
Imports System.Linq
 

        

        
 
Class Sample
Class Sample
~
  Shared rand As Random = New Random()
  ' ランダムに並べ替えるためのIComparer(Of Integer)を実装するクラス
-
  Class RandomComparer
-
    Implements IComparer(Of Integer)
-

          
-
    Public Function Compare(ByVal x As Integer, ByVal y As Integer) As Integer Implements IComparer(Of Integer).Compare
-
      ' -1, 0, +1いずれかの値をランダムに返す
-
      Return rand.Next(-1, 2)
-
    End Function
 

        

        
~
  Shared Function RandomKeySelector(ByVal val As Integer) As Integer
    Private rand As Random = New Random()
~
    ' valに関係なく、ランダムなキーを返す
  End Class
+
    Return rand.Next()
+
  End Function
 

        

        
 
  Shared Sub Main()
  Shared Sub Main()
~
    Dim list As New List(Of Integer)(New Integer() {0, 1, 2, 3, 4, 5, 6, 7, 8, 9})
    Dim arr As Integer() = New Integer() {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
 

        

        
 
    ' シャッフル
    ' シャッフル
~
    For Each val As Integer In list.OrderBy(AddressOf RandomKeySelector)
    Array.Sort(arr, New RandomComparer())
-

          
-
    For Each val As Integer In arr
 
      Console.Write("{0}, ", val)
      Console.Write("{0}, ", val)
 
    Next
    Next
 
    Console.WriteLine()
    Console.WriteLine()
1434,36 1445,31
 
#tabpage-end
#tabpage-end
 

        

        
 
#prompt(実行結果の例){{
#prompt(実行結果の例){{
~
9, 0, 6, 3, 4, 5, 8, 1, 7, 2, 
7, 8, 9, 4, 3, 1, 0, 2, 5, 6, 
 
}}
}}
 

        

        
~
一方、Array.Sortメソッドではこのような方法は使えません。 次の例では、Array.Sortメソッドに毎回異なる結果を返す&msdn(netfx,type,System.Collections.Generic.IComparer`1){IComparer<T>};を指定することで配列をシャッフルしようとしています。 IComparer<T>は、Comparision<T>デリゲートと同様の大小関係を定義するメソッドをクラスに実装するためのインターフェイスです。 大小関係をランダムにすることで一見シャッフル出来るように思えますが、実際にArray.Sortメソッドを呼び出すと、場合によっては大小関係に矛盾が生じて例外がスローされるため、期待通りには動作しません。
OrderByメソッドの場合も同様に、ランダムなキーを返すようにすることでコレクションをシャッフルすることが出来ます。 次の例ではOrderByにランダムなキーを与えてListをシャッフルしています。
 

        

        
 
#tabpage(C#)
#tabpage(C#)
 
#code(cs){{
#code(cs){{
 
using System;
using System;
 
using System.Collections.Generic;
using System.Collections.Generic;
-
using System.Linq;
 

        

        
 
class Sample {
class Sample {
~
  // ランダムに並べ替えるためのIComparer<int>を実装するクラス
  static Random rand = new Random();
+
  class RandomComparer : IComparer<int> {
+
    public int Compare(int x, int y)
+
    {
+
      // -1, 0, +1いずれかの値をランダムに返す
+
      return rand.Next(-1, 2);
+
    }
 

        

        
~
    private Random rand = new Random();
  static int RandomKeySelector(int val)
-
  {
-
    // valに関係なく、ランダムなキーを返す
-
    return rand.Next();
 
  }
  }
 

        

        
 
  static void Main()
  static void Main()
 
  {
  {
~
    int[] arr = new int[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    List<int> list = new List<int>(new int[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9});
 

        

        
~
    // シャッフル
    foreach (int val in list.OrderBy(RandomKeySelector)) {
+
    Array.Sort(arr, new RandomComparer());
+

          
+
    foreach (int val in arr) {
 
      Console.Write("{0}, ", val);
      Console.Write("{0}, ", val);
 
    }
    }
 
    Console.WriteLine();
    Console.WriteLine();
1474,27 1480,21
 
#code(vb){{
#code(vb){{
 
Imports System
Imports System
 
Imports System.Collections.Generic
Imports System.Collections.Generic
-
Imports System.Linq
 

        

        
 
Class Sample
Class Sample
~
  ' ランダムに並べ替えるためのIComparer(Of Integer)を実装するクラス
  Shared rand As Random = New Random()
+
  Class RandomComparer
+
    Implements IComparer(Of Integer)
 

        

        
~
    Public Function Compare(ByVal x As Integer, ByVal y As Integer) As Integer Implements IComparer(Of Integer).Compare
  Shared Function RandomKeySelector(ByVal val As Integer) As Integer
~
      ' -1, 0, +1いずれかの値をランダムに返す
    ' valに関係なく、ランダムなキーを返す
~
      Return rand.Next(-1, 2)
    Return rand.Next()
~
    End Function
  End Function
+

          
+
    Private rand As Random = New Random()
+
  End Class
 

        

        
 
  Shared Sub Main()
  Shared Sub Main()
~
    Dim arr As Integer() = New Integer() {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
    Dim list As New List(Of Integer)(New Integer() {0, 1, 2, 3, 4, 5, 6, 7, 8, 9})
 

        

        
 
    ' シャッフル
    ' シャッフル
~
    Array.Sort(arr, New RandomComparer())
    For Each val As Integer In list.OrderBy(AddressOf RandomKeySelector)
+

          
+
    For Each val As Integer In arr
 
      Console.Write("{0}, ", val)
      Console.Write("{0}, ", val)
 
    Next
    Next
 
    Console.WriteLine()
    Console.WriteLine()
1503,19 1503,13
 
}}
}}
 
#tabpage-end
#tabpage-end
 

        

        
~
#prompt(実行結果の例 (大小関係に矛盾が生じなかった場合)){{
#prompt(実行結果の例){{
~
7, 8, 9, 4, 3, 1, 0, 2, 5, 6, 
9, 0, 6, 3, 4, 5, 8, 1, 7, 2, 
 
}}
}}
 

        

        
~
#prompt(実行結果の例 (大小関係に矛盾が生じた場合)){{
より適切な乱数の取得については[[programming/netfx/mathematics/1_random]]、その他のシャッフルの実装例については[[programming/tips/shuffle_array]]を参照してください。
~
ハンドルされていない例外: System.ArgumentException: IComparer.Compare() メソッドから矛盾する結果が返されたため、並べ替えできません。値をそれ自体と比較したときに等しい結果にならないか、またはある値を別の値と繰り返し比較したときに異なる結果が生じます。x: '0'、x の型: 'Int32'、IComparer: ''。

          
+
   場所 System.Collections.Generic.GenericArraySortHelper`1.Sort(T[] keys, Int32 index, Int32 length, IComparer`1 comparer)
+
   場所 System.Array.Sort[T](T[] array, Int32 index, Int32 length, IComparer`1 comparer)
+
   場所 System.Array.Sort[T](T[] array, IComparer`1 comparer)
+
   場所 Sample.Main()
+
}}
 

        

        
+
その他のシャッフルの実装例については[[programming/tips/shuffle_array]]、より適切な乱数の取得については[[programming/netfx/mathematics/1_random]]、IComparer<T>については[[programming/netfx/comparison/0_comparison]]を参照してください。
 

        

        
 
*大文字小文字の違いを考慮したソート
*大文字小文字の違いを考慮したソート
 
文字列をソートする際、場合によっては大文字小文字の違いをどう扱うか厳密に決める必要が出て来ます。 その場合は、&msdn(netfx,type,System.StringComparer){StringComparer};を使ってどう扱うかを指定することができます。 Sortメソッド、OrderByメソッドともにIComparerを引数に取ることができ、これにStringComparerを指定することで、文字列比較の際の動作を指定できます。
文字列をソートする際、場合によっては大文字小文字の違いをどう扱うか厳密に決める必要が出て来ます。 その場合は、&msdn(netfx,type,System.StringComparer){StringComparer};を使ってどう扱うかを指定することができます。 Sortメソッド、OrderByメソッドともにIComparerを引数に取ることができ、これにStringComparerを指定することで、文字列比較の際の動作を指定できます。

programming/netfx/attributes/index.wiki.txt

current previous
12,47 12,8
 

        

        
 
つまり、プログラムと深い関係がある情報(メタデータ)を、言語の機能を拡張することなく記述することができるのが属性です。 また、属性を採用することにより言語仕様の拡張をする必要がなくなるので、Visual C++とBorland C++などのように、拡張した機能によって言語間の互換性が失われると言う心配もありません。
つまり、プログラムと深い関係がある情報(メタデータ)を、言語の機能を拡張することなく記述することができるのが属性です。 また、属性を採用することにより言語仕様の拡張をする必要がなくなるので、Visual C++とBorland C++などのように、拡張した機能によって言語間の互換性が失われると言う心配もありません。
 

        

        
+
**属性の具体例
+
.NET Frameworkには様々な機能を持った属性が用意されています。 代表的なものとして&msdn(netfx,type,System.Runtime.InteropServices.DllImportAttribute){DllImportAttribute};(DllImport属性)があります。 この属性はC#やVBからプラットフォームAPIの呼び出しを行うために使うもので、VB6以前に存在したDeclare Sub/Functionによる定義に変わるものです。 この属性を使うことで、呼び出したいAPIが含まれるDLLを指定する他、呼び出す際の呼び出し規約、文字列を渡す際の文字セットの指定などを行うことができます。 実行時にはこの属性で指定されたとおりにDLLがロードされ、APIを呼び出す際の文字セットの変換等といった処理が自動的に行われます。 これにより複雑な処理を記述することなく、APIの呼び出しが行えるようになります。
+

          
+
次のコードではAPI関数の&msdn(netfx,id,cc429896){LockWorkStation};を呼び出しています。 DllImport属性に続けて通常のメソッドと似た形式で宣言している箇所が、API呼び出しの宣言部です。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.Runtime.InteropServices;
+

          
+
class Sample {
+
  [DllImport("user32.dll")]
+
  private static extern bool LockWorkStation();
+

          
+
  static void Main()
+
  {
+
    // 画面をロックする
+
    LockWorkStation();
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.Runtime.InteropServices
+

          
+
Class Sample
+
  <DllImport("user32.dll")> _
+
  Private Shared Function LockWorkStation() As Boolean
+
  End Function
+

          
+
  Shared Sub Main()
+
    ' 画面をロックする
+
    LockWorkStation()
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
 
**.NET Frameworkで用意されている属性
**.NET Frameworkで用意されている属性
~
DllImport属性の他にも、.NET Frameworkには様々な属性が存在します。 よく使われるものとして次のような属性があります。 属性の具体的な使い道を理解するには以下のページが参考になるかもしれません。
.NET Frameworkには様々な機能を持った属性が存在します。 その中でもよく使われるものに次の属性があります。 属性の具体的な使い道を理解するには以下のページが参考になるかもしれません。
 

        

        
 
-[[programming/netfx/structlayout_fieldoffset]] - StructLayout属性、FieldOffset属性など
-[[programming/netfx/structlayout_fieldoffset]] - StructLayout属性、FieldOffset属性など
 
-[[programming/netfx/serialization]] - Serializable属性、NonSerialized属性など
-[[programming/netfx/serialization]] - Serializable属性、NonSerialized属性など

programming/netfx/basictypes/index.wiki.txt

current previous
270,107 270,11
 

        

        
 
なお、独自に定義した構造体の場合は、StructLayout属性でLayoutKind.SequentialまたはLayoutKind.Explicitを指定する必要があります。 詳しくは[[programming/netfx/structlayout_fieldoffset]]を参照してください。
なお、独自に定義した構造体の場合は、StructLayout属性でLayoutKind.SequentialまたはLayoutKind.Explicitを指定する必要があります。 詳しくは[[programming/netfx/structlayout_fieldoffset]]を参照してください。
 

        

        
+

          
+

          
+
*リテラルとサフィックス
+
数値および文字列のリテラル(値をそのまま記述したもの)にサフィックスを付けることで、リテラルの型を明示的に指定することが出来ます。 また、VBではサフィックスの他にも型文字と呼ばれる記号を付けることでも型を指定することが出来ます。 なお、以下の表中では明記していませんが、VBでもサフィックスを小文字で指定できます。
+

          
+
特にリテラルを指定しない場合、数値型ではint/Integer、実数型ではdouble/Doubleとして扱われ、代入に際しては代入先の型に変換されます。
+

          
+
|*サフィックスとリテラルの例
+
|~.NET Framework|>|>|~C#|>|>|>|~VB|
+
|~型|~型|~サフィックス|~リテラルの例|~型|~サフィックス|~型文字|~リテラルの例|
+
|>|>|>|>|>|>|>|~整数型|
+
|~&msdn(netfx,type,System.SByte);|~sbyte|-|-|~SByte|-|-|-|
+
|~&msdn(netfx,type,System.Int16);|~short|-|-|~Short|S|-|1024S|
+
|~&msdn(netfx,type,System.Int32);|~int|-|100000|~Integer|I|%|100000&br;100000I&br;100000%|
+
|~&msdn(netfx,type,System.Int64);|~long|L/l|200L&br;3000000000l|~Long|L|&|200L&br;3000000000&|
+
|~&msdn(netfx,type,System.Byte);|~byte|-|-|~Byte|-|-|-|
+
|~&msdn(netfx,type,System.UInt16);|~ushort|-|-|~UShort|US|-|2048US|
+
|~&msdn(netfx,type,System.UInt32);|~uint|u/U|12u&br;12U|~UInteger|UI|-|12UI|
+
|~&msdn(netfx,type,System.UInt64);|~ulong|ul/LUなど&br;(大文字小文字・UとLの順序は自由)|200ul&br;3000000000Lu|~ULong|UL|-|3000000000UL|
+
|>|>|>|>|>|>|>|~実数型|
+
|~&msdn(netfx,type,System.Single);|~float|f/F|1.0f&br;1.0F|~Single|F|!|1.0F&br;1.0!|
+
|~&msdn(netfx,type,System.Double);|~double|d/D|3.14&br;3.14d&br;3.14D|~Double|R|#|3.14&br;3.14R&br;3.14#|
+
|~&msdn(netfx,type,System.Decimal);|~decimal|m/M|0.66666666m&br;0.66666666M|~Decimal|D|@|0.66666666D&br;0.66666666@|
+
|>|>|>|>|>|>|>|~文字・文字列型|
+
|~&msdn(netfx,type,System.Char);|~char|-|'A'|~Char|C|-|"A"C|
+
|~&msdn(netfx,type,System.String);|~string|-|"ABC"|~String|-|-|"ABC"|
+
|~型|~型|~サフィックス|~リテラルの例|~型|~サフィックス|~型文字|~リテラルの例|
+
|~.NET Framework|>|>|~C#|>|>|>|~VB|
+

          
+
16進数・8進数表記の整数リテラルを記述する場合でも、プレフィックスと組み合わせてサフィックスを付けることで型を指定することが出来ます。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    // 10進数リテラルとサフィックス
+
    Console.WriteLine("{0} {1}", 100,  (100).GetType());
+
    Console.WriteLine("{0} {1}", 100u, (100u).GetType());
+
    Console.WriteLine("{0} {1}", 100L, (100L).GetType());
+

          
+
    // 16進数リテラルとサフィックス
+
    Console.WriteLine("{0} {1}", 0x100,  (0x100).GetType());
+
    Console.WriteLine("{0} {1}", 0x100u, (0x100u).GetType());
+
    Console.WriteLine("{0} {1}", 0x100L, (0x100L).GetType());
+
  }
+
}
+
}}
+

          
+
#prompt(実行結果){{
+
100 System.Int32
+
100 System.UInt32
+
100 System.Int64
+
256 System.Int32
+
256 System.UInt32
+
256 System.Int64
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+

          
+
Class Sample
+
  Shared Sub Main()
+
    ' 10進数リテラルとサフィックス
+
    Console.WriteLine("{0} {1}", 100,   (100).GetType())
+
    Console.WriteLine("{0} {1}", 100UI, (100UI).GetType())
+
    Console.WriteLine("{0} {1}", 100L,  (100L).GetType())
+

          
+
    ' 16進数リテラルとサフィックス
+
    Console.WriteLine("{0} {1}", &H100,   (&H100).GetType())
+
    Console.WriteLine("{0} {1}", &H100UI, (&H100UI).GetType())
+
    Console.WriteLine("{0} {1}", &H100L,  (&H100L).GetType())
+

          
+
    ' 8進数リテラルとサフィックス
+
    Console.WriteLine("{0} {1}", &O100,   (&O100).GetType())
+
    Console.WriteLine("{0} {1}", &O100UI, (&O100UI).GetType())
+
    Console.WriteLine("{0} {1}", &O100L,  (&O100L).GetType())
+
  End Sub
+
End Class
+
}}
+

          
+
#prompt(実行結果){{
+
100 System.Int32
+
100 System.UInt32
+
100 System.Int64
+
256 System.Int32
+
256 System.UInt32
+
256 System.Int64
+
64 System.Int32
+
64 System.UInt32
+
64 System.Int64
+
}}
+
#tabpage-end
+

          
 
*定数
*定数
 
基本データ型には、最大値・最小値などの定数を表す静的フィールドが用意されています。
基本データ型には、最大値・最小値などの定数を表す静的フィールドが用意されています。
 

        

        
 
**最大値・最小値
**最大値・最小値
~
MaxValue・MinValueフィールドを参照することで、各型の最大値・最小値を取得することができます。 これらのフィールドは、.NET Frameworkの型名・言語の型名のどちらでも参照できます(当然、値は同じです)。 また、Int32・Int64等は''実行環境が32ビットか64ビットかどうかに関わらず、常に32ビット・64ビット''であるため、実行環境によってMaxValue・MinValueフィールドの値が変わるということはありません。
MaxValue・MinValueフィールドを参照することで、各型の最大値・最小値を取得することができます。 これらのフィールドは、.NET Frameworkの型名・言語の型名のどちらでも参照できます(当然、値は同じです)。
 

        

        
 
#tabpage(C#)
#tabpage(C#)
 
#code(cs){{
#code(cs){{

programming/netfx/obsoletion/index.wiki.txt

current previous
20,6 20,7
 
#tabpage(C#)
#tabpage(C#)
 
#code(cs){{
#code(cs){{
 
using System;
using System;
-

          
 
using System.Diagnostics;
using System.Diagnostics;
 

        

        
 
class Sample
class Sample
70,13 71,7
 
このコードをコーディングしているときには、IDE上に次のような警告が表示されます。
このコードをコーディングしているときには、IDE上に次のような警告が表示されます。
 
#ref(0.png,Sub OldMethod&#x28;message As String&#x29;は旧形式です: '将来サポートされなくなる可能性があります。 NewMethodを使用して下さい。')
#ref(0.png,Sub OldMethod&#x28;message As String&#x29;は旧形式です: '将来サポートされなくなる可能性があります。 NewMethodを使用して下さい。')
 

        

        
~
コンパイル時にもこれと同じ警告が発せられます。
コンパイル時にもこれと同じ警告が発せられます。 このように、Obsolete属性は互換性のために残してあるような仕様の古くなったコードに対して、使用しないように促す警告を発することができます。
+

          
+
#prompt(コンパイル時に出力される警告){{
+
test.cs(20,5): warning CS0618: 'Sample.OldMethod(string)' は古い形式です: '将来サポートされなくなる可能性があります。 NewMethodを使用して下さい。'
+
}}
+

          
+
このように、Obsolete属性は互換性のために残してあるような仕様の古くなったコードに対して、使用しないように促す警告を発することができます。
 

        

        
 
また、Obsolete属性が適用されているメソッドを使用した場合に、警告ではなくコンパイルエラーとしたい場合には次のようにします。
また、Obsolete属性が適用されているメソッドを使用した場合に、警告ではなくコンパイルエラーとしたい場合には次のようにします。
 

        

        
147,11 142,6
 

        

        
 
OlderMethodで指定しているObsolete属性のように、コンストラクタの二つ目の引数にtrueを指定します。 このようにすると、このメソッドを使用しようとした場合は警告ではなくエラーとなり、このメソッドを使用したコードをコンパイルしようとするとコンパイルエラーが発生します。
OlderMethodで指定しているObsolete属性のように、コンストラクタの二つ目の引数にtrueを指定します。 このようにすると、このメソッドを使用しようとした場合は警告ではなくエラーとなり、このメソッドを使用したコードをコンパイルしようとするとコンパイルエラーが発生します。
 

        

        
+
#prompt(コンパイル時に出力されるエラー・警告){{
+
test.cs(25,5): error CS0619: 'Sample.OlderMethod(string)' は古い形式です: 'このバージョンは使用しないで下さい。 NewMethodを使用して下さい。'
+
test.cs(27,5): warning CS0618: 'Sample.OldMethod(string)' は古い形式です: '将来サポートされなくなる可能性があります。 NewMethodを使用して下さい。'
+
}}
+

          
 
#ref(1.png,IDE上に表示されたコンパイルエラー・警告)
#ref(1.png,IDE上に表示されたコンパイルエラー・警告)
 

        

        
 
ここまでの例ではメソッドに対してObsolete属性を適用してきましたが、クラスや構造体など(アセンブリ、モジュール、パラメータ、戻り値以外)に対して適用することもできます。 次の例は、構造体に対してObsolete属性を適用したものです。
ここまでの例ではメソッドに対してObsolete属性を適用してきましたが、クラスや構造体など(アセンブリ、モジュール、パラメータ、戻り値以外)に対して適用することもできます。 次の例は、構造体に対してObsolete属性を適用したものです。
203,10 193,6
 
}}
}}
 
#tabpage-end
#tabpage-end
 

        

        
+
#prompt(コンパイル時に出力される警告){{
+
test.cs(18,5): warning CS0618: 'ARGB' は古い形式です: 'System.Drawing.Colorを使用して下さい。'
+
}}
+

          
 
IDE上には次のような警告が表示されます。
IDE上には次のような警告が表示されます。
 

        

        
 
#ref(2.png,ARGBは旧形式です: 'System.Drawing.Colorを使用して下さい。')
#ref(2.png,ARGBは旧形式です: 'System.Drawing.Colorを使用して下さい。')