![]() |
|
DOBON.NET > プログラミング道 > どぼん!の.NET
Tips > VB.NETユーザーのためのC#Tips
VB.NETユーザーのためのC#Tips- 全記事表示VB.NETユーザーのためのC#Tipsメニュー
C#でIsNumeric、IsDateに代わるものは?VBのIsNumeric関数は、指定されたデータが正しく倍精度浮動小数点数型(Double)に変換できる文字列であるか調べることができる関数です。Char構造体にはIsNumberやIsDigitというメソッドがありますが、これらは指定された文字が数字であるか調べるものであり、文字列には使えません。 C#でIsNumericの代わりになりそうな方法には、
などが考えられそうです。ここでは1と2の方法を紹介します。 1の方法は例えば次のようになります。ここではNumberStyles.AnyとNumberFormatInfo.InvariantInfoを指定していますが、必要に応じて変更してください(詳しくはヘルプをご覧ください)。
[VB.NET]
Dim str As String = "-12.34"
Dim d As Double
'doubleに変換できるか確かめる
If Double.TryParse(str, _
System.Globalization.NumberStyles.Any, _
System.Globalization.NumberFormatInfo.InvariantInfo, _
d) Then
Console.WriteLine("{0}は数字です。", str)
Else
Console.WriteLine("{0}は数字ではありません。", str)
End If
[C#]
string str = "-12.34";
double d;
//doubleに変換できるか確かめる
if (double.TryParse(str,
System.Globalization.NumberStyles.Any,
System.Globalization.NumberFormatInfo.InvariantInfo,
out d))
Console.WriteLine("{0}は数字です。", str);
else
Console.WriteLine("{0}は数字ではありません。", str);
次に2番目の方法です。これは例えば次のようになります。
[VB.NET]
Dim str As String = "-12.34"
Dim isnum As Boolean = True
'doubleに変換できるか確かめる
Try
Double.Parse(str)
Catch
isnum = False
End Try
'結果を表示
If isnum Then
Console.WriteLine("{0}は数字です。", str)
Else
Console.WriteLine("{0}は数字ではありません。", str)
End If
[C#]
string str = "-12.34";
bool isnum = true;
//doubleに変換できるか確かめる
try
{
double.Parse(str);
}
catch
{
isnum = false;
}
//結果を表示
if (isnum)
Console.WriteLine("{0}は数字です。", str);
else
Console.WriteLine("{0}は数字ではありません。", str);
次にIsDate関数です。VBのIsDate関数は、指定した文字列が日付型(Date)に変換可能か調べることができる関数です。IsDate関数の場合も先に示したIsNumeric関数の2〜4の方法が使えます。 次に2番目の方法を使った例を示します。
[VB.NET]
Dim str As String = "2000/1/1"
Dim isnum As Boolean = True
'DateTimeに変換できるか確かめる
Try
DateTime.Parse(str)
Catch
isnum = False
End Try
'結果を表示
If isnum Then
Console.WriteLine("{0}はDateTimeに変換できます。", str)
Else
Console.WriteLine("{0}はDateTimeに変換できません。", str)
End If
[C#]
string str = "2000/1/1";
bool isnum = true;
//DateTimeに変換できるか確かめる
try
{
DateTime.Parse(str);
}
catch
{
isnum = false;
}
//結果を表示
if (isnum)
Console.WriteLine("{0}はDateTimeに変換できます。", str);
else
Console.WriteLine("{0}はDateTimeに変換できません。", str);
C#でTypeOf...Is...に代わるものは?C#でVB.NETのTypeOf...Is式に代わるものは、is演算子です。is演算子は (expression) is (type) のように使用し、(expression)がnullでなく、(expression)を(type)にキャストできる場合にtrueを返します。is演算子は参照変換、ボックス化変換、ボックス化解除変換だけを考慮し、ユーザー定義変換などの変換は、考慮しません。(TypeOf...Is式も同様だと思いますが、詳しくは分かりません。) また、is演算子と同様の使い方でas演算子を使う場合もあります。as演算子は型の変換を実行しますが、キャストと違い、変換できなかった時に例外を発生せずにnullを返すため、nullを返したかを調べることにより、型の互換性を調べることができます。ただし、as演算子は参照変換とボックス化変換だけを実行し、ユーザー定義変換などの変換は実行できません。 なお、ユーザー定義変換も考慮して調べるには、キャストして例外が発生するか調べることになるでしょう。 C#でCreateObjectと同じことをするには?C#でVB.NETのCreateObject関数と同じことをするには、Type.GetTypeFromProgIdメソッドで型を取得し、Activator.CreateInstanceメソッドなどによりインスタンスを作成します。 次にVB.NETのCreateObject関数とほぼ同様の機能を有するメソッドのコードを示します。
[C#]
/// <summary>
/// COMオブジェクトへの参照を作成および取得する
/// </summary>
/// <param name="progId">作成するオブジェクトのプログラムID</param>
/// <param name="serverName">
/// オブジェクトが作成されるネットワーク サーバーの名前
/// </param>
/// <returns>作成されたCOMオブジェクト</returns>
public static object CreateObject(string progId, string serverName)
{
Type t;
if (serverName == null || serverName.Length == 0)
t = Type.GetTypeFromProgID(progId);
else
t = Type.GetTypeFromProgID(progId, serverName, true);
return Activator.CreateInstance(t);
}
/// <summary>
/// COMオブジェクトへの参照を作成および取得する
/// </summary>
/// <param name="progId">作成するオブジェクトのプログラムID</param>
/// <returns>作成されたCOMオブジェクト</returns>
public static object CreateObject(string progId)
{
return CreateObject(progId, null);
}
ただし、C#ではVB.NETと違い、暗黙の遅延バインディングができませんので、取得したCOMオブジェクトのプロパティやメソッドを呼び出すには、Type.InvokeMemberメソッドを使用する必要があります。詳しくは、こちらをご覧ください。 C#でSplit関数の代わりになるものは?StringクラスのSplitメソッドは区切り文字としてChar型でしか指定できないため、文字列で区切り文字を指定できるVBのSplit関数とは大きく異なります。ではVBのSplit関数のように区切り文字を文字列(string型)で指定できるようにするにはどうすればよいのでしょうか? これにはMicrosoft.VisualBasic.StringsクラスのSplitメソッドを使う方法と、Regexクラス(System.Text.RegularExpression名前空間)のSplitメソッドを使う方法が考えられます。しかしこれらはかなり処理速度が遅いです。分割したい文字列内の区切り文字(列)をいったん適当な1文字(分割したい文字列内の分割したくない位置に絶対現れることのない文字)に置換した後、StringクラスのSplitメソッドにより分割した方が圧倒的に速いケースも多いようです。 次のサンプルではRegex.Split、VisualBasic.Strings.Split、string.Splitそれぞれのメソッドを使ってstring型データを改行文字列("\r\n")で分割したときにかかった時間を計っています。
[C#]
//いろいろな方法でstring型データを改行文字列("\r\n")で分割し
//その時間を計る
//テキストファイルをstrTextに読み込む
string strFileName = "REDIST.TXT";
System.IO.FileStream fs = new System.IO.FileStream(strFileName,
System.IO.FileMode.Open);
System.IO.StreamReader sr = new System.IO.StreamReader(fs,
System.Text.Encoding.GetEncoding(932));
string strText = sr.ReadToEnd();
sr.Close();
int t1, t2, t3;
string [] s1, s2, s3;
//Regex.Splitで分割する
t1 = System.Environment.TickCount;
s1 = System.Text.RegularExpressions.Regex.Split(strText,
"\r\n");
t1 = System.Environment.TickCount - t1;
//VisualBasic.Strings.Splitで分割する
t2 = System.Environment.TickCount;
s2 = Microsoft.VisualBasic.Strings.Split(strText, "\r\n", -1,
Microsoft.VisualBasic.CompareMethod.Binary);
t2 = System.Environment.TickCount - t2;
//string.Splitで分割する
t3 = System.Environment.TickCount;
s3 = strText.Replace("\r\n", "\n").Split('\n');;
t3 = System.Environment.TickCount - t3;
//結果を表示
Console.WriteLine("Regex.Split: {0}", t1);
Console.WriteLine("VisualBasic.Strings.Split: {0}", t2);
Console.WriteLine("string.Split: {0}", t3);
Console.WriteLine("Lines Count: {0}", s3.Length);
//表示例
//Regex.Split: 521
//VisualBasic.Strings.Split: 1452
//string.Split: 181
C#のイベント機能VBでイベント機能を利用するには、イベントを発生させるクラスでEventステートメントによりイベントを宣言し、RaiseEventステートメントによりイベントを発生させ、イベントを受信するクラスではWithEventsで変数を宣言することなどにより簡単に可能となる。これと同様のことをC#で行うにはどのようにすればよいのだろうか。 これがVBほど簡単にはいかない。ヘルプなどを調べると「デリゲート」やら「イベントハンドラ」などの「?」な言葉が並ぶ。ここではこれらの理屈は抜きにしてこれらを実現させる簡単な方法を考えてみる。 最も簡単な(?)イベント まず次のような超単純なクラス「SleepClass」を作ってみる。ここではまだイベントを使用していない。とりあえずStartメソッドを実行すると5秒間停止するだけである。
[C#]
public class SleepClass
{
public void Start()
{
System.Threading.Thread.Sleep(5000);
}
}
次に5秒停止後イベントが発生するようにしてみる。このときイベントが発生するだけで何もデータを返さないものとする。
[C#]
public class SleepClass
{
// データを持たないイベントデリゲートの宣言
//ここでは"Time"というイベントデリゲートを宣言する
public event EventHandler Time;
public void Start()
{
System.Threading.Thread.Sleep(5000);
if (Time != null)
{
//"Time"イベントの発生
Time(this, EventArgs.Empty);
}
}
}
イベントを受け取る側では次のように宣言する。ここではbutton1_ClickイベントによりSleepClassクラスのStartメソッドを呼び出し、イベント「Time」が発生するとSleepClass_Timeが呼び出され実行される。
[C#]
private void button1_Click(object sender, System.EventArgs e)
{
SleepClass clsSleep = new SleepClass();
//イベントハンドラの追加
clsSleep.Time += new EventHandler(this.SleepClass_Time);
clsSleep.Start();
}
private void SleepClass_Time(object sender, System.EventArgs e)
{
//イベントが発生したとき
MessageBox.Show("OK!");
}
ここでEventHandlerやEventArgsとは一体なんだろうという疑問が湧くだろうが、ここではあえてこれらの説明を省き、「こういうもの」としておこう。 これでほとんどの場合用が済んでしまうような気もするが、ヘルプにあるようにSleepClassを少し改良してみる。
[C#]
public class SleepClass
{
// データを持たないイベントデリゲートの宣言
public event EventHandler Time;
protected virtual void OnTime(EventArgs e)
{
if (Time != null)
{
Time(this, e);
}
}
public void Start()
{
System.Threading.Thread.Sleep(5000);
OnTime(EventArgs.Empty);
}
}
ここで変更された点といえばもちろん「protected virtual void OnTime(EventArgs e)」が追加されたことである。このSleepClassを継承して新たなクラスを作ることを考えればこうするべきということらしい。 以上説明はほとんどしなかったが、ここでの肝はすでに用意されているEventHandlerデリゲートと、EventArgsクラスを使ったことである。そのためにデリゲートの宣言と、返すデータのクラスを宣言する必要がなくなり、かなり簡略化ができた。しかしその分上記のような決まりきったやり方でしか使えないのが欠点といえる。 データを返すイベント さて次はデータを返すイベントを作成する方法を考える。実は上記の例で使用した「EventHandlerデリゲート」と「EventArgsクラス」はイベントがデータを持たないから使えたわけで、そうでなければこれらに代わるものを自分で新しく用意する必要がある。 返されるデータは上の例の「EventArgs」に代わる(から継承される)クラスになるため、結局その部分だけを書き換えることになる。下にその例を示す。
[C#]
//Timeイベントで返されるデータ
//ここではstring型のひとつのデータのみ返すものとする
public class TimeEventArgs : EventArgs
{
public string Message;
}
public class SleepClass
{
//デリゲートの宣言
//TimeEventArgs型のオブジェクトを返すようにする
public delegate void TimeEventHandler(object sender, TimeEventArgs e);
//イベントデリゲートの宣言
public event TimeEventHandler Time;
protected virtual void OnTime(TimeEventArgs e)
{
if (Time != null)
{
Time(this, e);
}
}
public void Start()
{
System.Threading.Thread.Sleep(5000);
//返すデータの設定
TimeEventArgs e = new TimeEventArgs();
e.Message = "終わったよ。";
//イベントの発生
OnTime(e);
}
}
次は呼び出す側。
[C#]
private void button1_Click(object sender, System.EventArgs e)
{
SleepClass clsSleep = new SleepClass();
clsSleep.Time += new SleepClass.TimeEventHandler(this.SleepClass_Time);
clsSleep.Start();
}
private void SleepClass_Time(object sender, TimeEventArgs e)
{
//返されたデータを取得し表示
MessageBox.Show(e.Message);
}
以上のようにデータを返さない単純なケースと比較して、返すデータを入れるTimeEventArgsクラスを使用するようにするための手間が余計に必要になる。ここで一番大事なのはイベントが発生したときに実行する関数(ここではSleepClass_Time)の2番目の引数の型が変更されることにより、以前使用していた「EventHandler」は使えなくなり、新しくデリゲートを宣言しなければいけないうところだろう。後は問題ないものと思う。 応用 いままではEventArgsの派生クラスを用いてデータを返していたが、必ずしもそうする必要はない。次の例ではEventArgsの派生クラスを使わずに文字列と整数を返しているが、やっていることは今までとまったく同じである。(ただし前に紹介したようなEventArgsの派生クラスを使った方法が.NETでは推奨された方法である。)
[C#]
public class SleepClass2
{
//デリゲートの宣言
public delegate void TimeEventHandler(string message, int number);
//イベントデリゲートの宣言
public event TimeEventHandler Time;
protected virtual void OnTime(string message, int number)
{
if (Time != null)
{
Time(message, number);
}
}
public void Start()
{
System.Threading.Thread.Sleep(5000);
//イベントの発生
OnTime("終わったっす。", 5000);
}
}
使用する側では次のようになる。
[C#]
private void button1_Click(object sender, System.EventArgs e)
{
SleepClass2 clsSleep = new SleepClass2();
clsSleep.Time += new SleepClass2.TimeEventHandler(this.SleepClass2_Time);
clsSleep.Start();
}
private void SleepClass2_Time(string message, int number)
{
MessageBox.Show(message + ":" + number.ToString());
}
Collectionに代わるものは?.NET Frameworkで用意されているコレクションクラスは、System.Collections名前空間にあります。この中から必要に応じて適当なクラスを選択して使用します。どのクラスを選択すべきかに関しては、ヘルプ「コレクション クラスの選択」で詳しく説明されています。 VBのCollectionに一番近いクラスは、.NET FrameworkではNameObjectCollectionBaseクラス (System.Collections.Specialized名前空間)であるようです。ただし、NameObjectCollectionBaseクラスは抽象クラスであるため、実際に使うためには派生クラスを作成しなければなりません。.NET FrameworkではNameObjectCollectionBaseクラスの派生クラスとして、NameValueCollectionクラスが用意されていますが、これは文字列のコレクションであり、同じキー名のアイテムを複数登録できるという違いがあります。 .NET Frameworkで実際によく使われるコレクションクラスは、ArrayListクラスか、Hashtableクラス(ともにSystem.Collections名前空間)です。ArrayListクラスはインデックスによってしか要素にアクセスできませんし、Hashtableクラスはキーによってしか要素にアクセスできません。 C#でReDim Preserveの代わりになるものは?ここではVBの"ReDim Preserve"と同じことをC#で行うにはどうすればよいか考えてみましょう。 まず順当なのは、変更したいサイズの配列を新たに作成し、その配列に要素をコピーするという方法です。次に要素数を5から10に増やす例を示します。
[C#]
//要素数5の配列を作る
int[] intArray = {0, 1, 2, 3, 4};
//要素数10の配列を作る
int[] newArray = new int[10];
//配列の要素をコピーする
Array.Copy(intArray, newArray,
Math.Min(intArray.Length, newArray.Length));
//できた配列をintArrayに戻す
intArray = newArray;
バイト型配列の場合、配列の大きさを頻繁に変更するならば、MemoryStreamオブジェクトを使うと便利です。MemoryStreamオブジェクトのコンストラクタに基になるバイト型配列を指定できますが、この場合、指定されたバイト型配列のサイズ以上の容量にすることが出来なくなります。 MemoryStreamオブジェクトを使えば、下記の例のように、簡単にバイト型配列を追加したり、サイズを変更することができます。
[C#]
//MemoryStreamオブジェクトの作成
System.IO.MemoryStream ms = new System.IO.MemoryStream();
//バイト型配列をMemoryStreamに追加する
byte[] bs1 = new byte[] {0, 1, 2, 3, 4};
ms.Write(bs1, 0, bs1.Length);
//さらに追加する
byte[] bs2 = new byte[] {5, 6, 7};
ms.Write(bs2, 0, bs2.Length);
//MemoryStreamの大きさを変更する
ms.SetLength(10);
//MemoryStreamの内容をバイト型配列に変換する
byte[] bs = ms.ToArray();
//閉じる
ms.Close();
VB.NET、C#変換表下の表ではVB.NETとC#とで同じ役割を果たしているであろうものをそれぞれを対応させて紹介しています。見やすくするため、分類のようなことをしていますが、これはかなりいい加減です。説明のほとんどはVB.NETの方のヘルプでの説明をのせています。 Visual Basic、Visual J#、C++、C#、JScriptの比較は、ヘルプの「各言語の比較」が参考になります。
C#でInputBox関数に代わるものは?C#にVBのInputBox関数と同じものは用意されていません。つまりは自分でダイアログを作成するしかなさそうです。ダイアログフォームの作成方法はこちらの「フォームにOKボタン、キャンセルボタンを付ける」を参考にしてください。 文字列を記述する時"\"を"\\"と書くのが面倒なときは?例えばString型の変数sに"C:\Dos\App\readme.txt"という文字列を代入したい時にVBでは s = "C:\Dos\App\readme.txt" と書くことが出来ますが、C#では次のように"\"を"\\"とする必要があります。 s = "C:\\Dos\\App\\readme.txt"; これはC#では"\"という文字があるとエスケープシーケンスが処理されてしまうためですが、これが面倒というケースもあります。そのような時は次のように@を付けることにより、エスケープシーケンスが処理されないように指定することができます。 s = @"C:\Dos\App\readme.txt"; このとき、"で囲まれた文字列の中に"という文字を入れるには、VBと同じように""と2回書きます。 C#でビープ音を鳴らすVBではBeep関数により、簡単にビープ音(一般の警告音)を鳴らすことが出来ます。C#で同じようにビープ音を鳴らすには、Microsoft.VisualBasic名前空間内InteractionクラスのBeepメソッドを使うか、あるいはWin32 APIのMessageBeep関数を使います。 次にWin32 APIのMessageBeep関数でビープ音を鳴らす例を示します。
[C#]
//ビープ音を鳴らす
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern int MessageBeep(uint n);
public static void Beep()
{
MessageBeep(0);
}
C#でLike演算子の代わりになるものは?C#にVBのLike演算子はありません。これと同等の処理をするには、Regexクラス(System.Text.RegularExpression名前空間)のIsMatchメソッドを使う方法(つまり正規表現を使う方法)があります。Like演算子の"*"、"?"、"#"はそれぞれ正規表現では".*"、"."、"\d"に置き換えることが出来ます。Like演算子の"[]"は正規表現でも"[]"で、Like演算子の"[!]"は正規表現では"[^]"と表現できます。 正規表現の"."は改行文字以外の文字を表すため、改行文字を含む文字列の比較では同一の結果とならないかもしれません。このような時は一致オプションにRegexOptions.Singlelineを指定し、単一行モードとします。このことにより、"."はすべての文字と一致するようになります。 さらに、Like演算子は2つの文字列が完全に一致するかを調べるのに対して、IsMatchメソッドは一致する箇所があるか調べるものです。よって、IsMatchメソッドでは検索パターン文字列の前後に"^"と"$"を付ける必要がありそうです。 当然ですが、検索パターン文字列に正規表現で使われるメタ文字が含まれているときは、これをエスケープしておかなければいけません。(これはRegex.Escapeメソッドを使ってできます。) 実際にこの変換を使用した例を下に示します。この例ではVBのLike演算子のヘルプでのサンプルをC#に変換してみました。
[C#]
//using System.Text.RegularExpressions;
//が宣言されているものとする
bool myCheck;
//myCheck = "F" Like "F"
myCheck = Regex.IsMatch("F", "^F$", RegexOptions.Singleline);
//myCheck: true
//myCheck = "F" Like "f"
myCheck = Regex.IsMatch("F", "^f$", RegexOptions.Singleline);
//myCheck: false
//myCheck = "F" Like "FFF"
myCheck = Regex.IsMatch("F", "^FFF$", RegexOptions.Singleline);
//myCheck: false
//myCheck = "aBBBa" Like "a*a"
myCheck =
Regex.IsMatch("aBBBa", "^a.*a$", RegexOptions.Singleline);
//myCheck: true
//myCheck = "F" Like "[A-Z]"
myCheck =
Regex.IsMatch("F", "^[A-Z]$", RegexOptions.Singleline);
//myCheck: true
//myCheck = "F" Like "[!A-Z]"
myCheck =
Regex.IsMatch("F", "^[^A-Z]$", RegexOptions.Singleline);
//myCheck: false
//myCheck = "a2a" Like "a#a"
myCheck =
Regex.IsMatch("a2a", "^a\\da$", RegexOptions.Singleline);
//myCheck: true
//myCheck = "aM5b" Like "a[L-P]#[!c-e]"
myCheck = Regex.IsMatch(
"aM5b", "^a[L-P]\\d[^c-e]$", RegexOptions.Singleline);
//myCheck: true
//myCheck = "BAT123khg" Like "B?T*"
myCheck = Regex.IsMatch(
"BAT123khg", "^B.T.*$", RegexOptions.Singleline);
//myCheck: true
//myCheck = "CAT123khg" Like "B?T*"
myCheck = Regex.IsMatch(
"CAT123khg", "^B.T.*$", RegexOptions.Singleline);
//myCheck: false
Disposeメソッドが確実に呼び出されるようにするC#にはDisposeメソッドを確実に呼び出すようにする簡単な方法が用意されています。それはusingステートメントを使う方法です。次の例ではFontクラスのインスタンスを作成し、その後クリーンアップしています。
[C#]
using System.Drawing;
class a
{
public static void Main()
{
using (Font MyFont = new Font("Arial", 10.0f))
{
//MyFont を使用したコードがあるものとする
} //コンパイラが MyFont の Dispose を呼び出す
}
}
これと同じものをVB.NETで書くと、Try...Finally文のFinallyにおいてDisposeメソッドを呼び出すことになります。
[VB.NET]
Imports System.Drawing
Class a
Public Shared Sub Main()
Dim MyFont As New Font("Arial", 10.0F)
Try
'MyFont を使用したコードがあるものとする
Finally
'MyFont の Dispose を呼び出す
If Not MyFont Is Nothing Then
MyFont.Dispose()
End If
End Try
End Sub
End Class
IIf関数の代わりになるものは?C#でVBのIIf関数と同じ機能を持ったものが?:演算子です(というかIIf関数が?:演算子のまねでしょうけど)。 VBの s = IIf(i > 100, "Large", "Small") はC#で次のようにかけます。 s = i > 100 ? "Large" : "Small"; |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Copyright 2002-2005 DOBON!. All rights reserved. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||