Claude Media
Claude CodeでVB.NETをC#に変換する — 挙動の差を拾うレビュー役の置き方

Claude CodeでVB.NETをC#に変換する — 挙動の差を拾うレビュー役の置き方

VB.NETをC#へ変換したあと、コンパイルが通っても残る挙動の差を、Claude Codeのレビュー用サブエージェントで拾う手順です。Option Strict・配列の宣言・Nothingなどを扱います。

Claude CodeでVB.NETをC#に変換する — 挙動の差を拾うレビュー役の置き方

VB.NETのコードをC#へ変換すると、ビルドは通るのに結果が少し違う、という残り方をします。構文の書き換えは変換ツールでもClaude Codeでも進みます。残るのは、VBが暗黙にやっていた処理をC#が同じようにはやらない箇所です。

この記事は、機械変換とは別に「挙動の差だけを見る」レビュー用サブエージェントを置き、プロジェクト単位で回す分け方をまとめます。拾う対象は、Option Strict、配列の宣言、Nothing、大文字小文字、AndとAndAlsoの5つです。

変換後に残る差は、コンパイルでは見つからない

.NET Frameworkから現行の .NETへの移行そのものは、Microsoft Learnの「Upgrade .NET apps overview」が道筋を整理しています。ここに載っている支援ツールは、GitHub Copilot app modernizationエージェントです。.NET Upgrade Assistantは同ページで非推奨とされ、今後の開発は行われないと書かれています。ただしこれは .NETのバージョン移行の話で、言語をVBからC# に変える作業は別の問題です。

言語の変換で厄介なのは、コンパイルエラーにならない差です。たとえばVBの Nothing は、値型に代入すると既定値になります。C# の null は同じ場面でコンパイルエラーです。エラーになる差は直せば終わります。エラーにならない差は、テストか目視でしか見つかりません。

そこで作業を2つに割ります。

  • 構文の置き換え: 変換ツールか、メインの会話でClaude Codeに任せる
  • 挙動の差の洗い出し: 変換前後のファイルを並べて読む、読み取り専用のレビュー役に任せる

後者を別のコンテキストに出す理由は、サブエージェントの仕様から説明できます。サブエージェントは長い出力を自分のコンテキストに閉じ込め、要約だけを返します。差分の読み込みは出力が多くなりやすく、メインの会話を圧迫しません。

プロジェクト単位で変換し、1プロジェクトずつ確かめる

ソリューション全体を一度に変換すると、差の出どころが追えなくなります。.vbproj 1つを単位にして、次の順で進めます。

手順

1プロジェクトの変換と検証

  1. 1

    元の VB を残す

    変換前のコミットに印を付けます。レビュー役は、このコミットのVBと変換後のC# を並べて読みます。

  2. 2

    機械変換する

    変換ツールの出力をそのまま取り込みます。ここでは手を入れず、ビルドが通るところまでを一区切りにします。

  3. 3

    レビュー役を呼ぶ

    変換した .cs ごとに、対応する元の .vb を渡して挙動の差を列挙させます。

  4. 4

    差をテストに変える

    指摘された箇所は、直す前にテストで固定します。VB側の実行結果が基準値になります。

  5. 5

    次のプロジェクトへ進む

    他から参照されないプロジェクトを先に、共通ライブラリを後に回すと、指摘の影響範囲が小さく済みます。

ステップ5の順序は、運用上の目安として挙げたものです。依存の深いライブラリから変換する構成にも利点があり、固定された順序ではありません。

VBとC# で意味が変わる5つの箇所

レビュー役に渡す観点は、Microsoft LearnのVB言語リファレンスに書かれている挙動から選びます。下の表は、その要点をC# 側から見た「確認の合図」に並べ直したものです。

観点VBでの挙動変換後に確認すること
Option StrictVBでの挙動暗黙の縮小変換・遅延バインディングが、Onのときだけコンパイルエラー変換後に確認すること元ファイルがOffだったか。Offなら暗黙変換が実行時に効いていた
配列の宣言VBでの挙動Dim a(4) は上限を指定する。要素は5個変換後に確認することnew T[4] と機械的に書き換えていないか
NothingVBでの挙動値型に代入すると既定値になる変換後に確認することnull 代入や == null 比較に置き換わっていないか
大文字小文字VBでの挙動識別子は区別しない。文字列比較はOption Compare次第変換後に確認すること文字列の == が意図どおりか
AndとAndAlsoVBでの挙動Andは両辺を必ず評価する変換後に確認すること& を && に変えて副作用が消えていないか

Option StrictがOffのままだった箇所

Option Strict Onでは、暗黙の縮小変換、遅延バインディング、Objectへの暗黙の型付けがコンパイルエラーになります。逆に言うと、これがOffのファイルには、その3つが残っている可能性があります。

Option Strictは、ファイルにもプロジェクト設定にも指定がなければOffとして扱われます。Offのとき、型指定のない Dim qty はコンパイルエラーにならず、Nothingが入った変数になります。ここがC# では型付きの宣言に変わるので、変換ツールが何を推論したかを、レビュー役に確認させる価値があります。

見る順番は次のとおりです。先に、各 .vb ファイルの先頭と .vbproj からOption Strictの状態を拾います。次に、Offのファイルだけ、変数宣言と数値の代入を重点的に読ませます。

「1始まりの配列」ではなく、上限指定の配列

VBの配列は1始まりだと思っていると、レビューの焦点を外します。Microsoft Learnによれば、インデックスは0から始まり、VBの構文でサイズを決めるときに指定するのは要素数でなく最も大きいインデックスです。Dim numbers(4) As Integer は5要素の配列です。

前と後

配列宣言の機械的な書き換えで要素が1つ消える

BEFORE

VB.NET

Dim buffer(9) As Byte   ' 10要素(0〜9)
AFTER

C#(誤った変換)

var buffer = new byte[9];   // 9要素。最後の1要素が消える

正しい変換は new byte[10] です。数字をそのまま写すと、境界の1要素を失います。実行しても例外が出るのは末尾の添字へアクセスしたときだけなので、テストで末尾まで届かないと見逃します。

Nothingはnullとは限らない

Microsoft Learnは、非Nullableの値型でVBのNothingがC# のnullと異なると明記しています。値型の変数にNothingを代入すると、その型の既定値になります。C# で値型にnullを代入するとコンパイルエラーです。

エラーになるなら見つけやすいのですが、機械変換は default や null を文脈で選びます。参照型と Nullable では null で正しくても、Integer や Boolean のNothing代入が null へ化けていないかは、レビュー役に全件当たらせる項目です。Dim something = Nothing のように型指定がない宣言は、Option StrictとOption InferがどちらもOnでもエラーにならず、型がObjectになります。この宣言も変換後の型を確かめる対象です。

大文字小文字の扱い

VBの識別子は大文字小文字を区別しません。ABC と abc は同じ要素として扱われます。C# は区別するので、VB側で表記が揺れていた変数名やメンバー名は、変換後に別の名前に分かれるか、変換ツールが片方に寄せたかを見ます。

文字列の比較にも別の軸があります。VBはOption Compareで、既定がBinaryです。Textにしているファイルでは "A" = "a" がTrueになります。このファイルをC# に変換して == を使うと、大文字小文字の違いが結果に出ます。Option Compare Text を含むファイルは、レビュー役に最優先で渡す対象です。

Andは短絡評価をしない

VBのAndは両辺を必ず評価します。AndAlsoは左辺がFalseなら右辺を評価しません。C# の && は後者に近い動きです。And を && に変えると、右辺のメソッド呼び出しが飛ばされる場合があります。右辺に副作用がある式は、変換後も呼び出しが残っているか確認します。

レビュー用サブエージェントを定義する

プロジェクトの .claude/agents/ に置いたサブエージェントは、リポジトリごとにバージョン管理できます。VBからC# への変換は特定のコードベースに閉じた作業なので、ユーザー全体用の置き場所より、プロジェクト用の置き場所が向きます。

読み取り専用にするため、tools にEditとWriteを入れません。次の定義は、サブエージェントのドキュメントにあるコードレビュー役の書き方に合わせた例です。

---
name: vb-cs-diff-reviewer
description: VB.NETからC#へ変換したファイルを、元のVBと突き合わせて挙動の差を列挙する。変換直後に使う。
tools: Read, Grep, Glob
model: inherit
---
 
あなたはVB.NETからC#への変換をレビューする。コードは書き換えない。
 
呼ばれたら、指定された .cs と、対応する元の .vb を両方読む。
次の観点で、挙動が変わりうる箇所だけを挙げる。
 
1. Option Strict / Option Infer / Option Compare の状態と、変換後の型・比較
2. 配列宣言 Dim a(n) の要素数(n+1)と、new T[n] の n の一致
3. 値型への Nothing 代入が、null や default のどちらに変換されたか
4. 識別子の大文字小文字の揺れが、別の名前に分かれていないか
5. And / Or を &, | に写したか、AndAlso / OrElse を && / || に写したか
 
出力は、ファイル名・行・VBの挙動・C#の挙動・確認方法の順に1件ずつ。
差がなければ「差なし」と書く。推測は推測と明記する。

description は、Claudeがこのサブエージェントへ委任する場面を判断する材料です。変換直後に使うと書いておくと、変換の作業が終わった時点で自動的に呼ばれやすくなります。確実に呼びたい場合は、メッセージ内で名前を指定します。

@"vb-cs-diff-reviewer (agent)" src/Billing の変換結果を、
legacy/Billing の元VBと突き合わせてレビューして

@ メンションは、そのサブエージェントを必ず走らせます。ただし、メッセージ全体はClaudeに渡り、サブエージェントへの依頼文はClaudeが組み立てます。ファイルの対応(新旧のパス)は、会話の側で明示しておきます。

CLAUDE.mdの規約も効く

サブエージェントは、ExploreとPlanを除き、CLAUDE.mdを含む初期コンテキストを読み込みます。「VBの元ソースは legacy/ に置く」「変換済みは src/ に置く」といった配置の約束をCLAUDE.mdに書くと、依頼のたびに新旧の対応を説明しなくて済みます。逆に、サブエージェントがCLAUDE.mdを読まなくてよいなら、omitClaudeMd で外せます。

指摘をテストに変えて、基準値を固定する

レビュー役の出力は、読み取り専用の所見です。所見が正しいかどうかは、実行して確かめます。方法は、MATLABからPythonへの移植で使う「基準値を先に固定する」やり方と同じです。MATLABからPythonへの移植記事の流れを、言語変換に当てはめます。

  1. 元のVBプロジェクトで、疑わしい関数を代表入力で実行し、戻り値を記録する
  2. その値を期待値にしたテストを、C# 側に書く
  3. 失敗するテストを見てから、C# を直す

配列の例なら、テストは次の形です。クラス名は例示用の仮名です。

[Fact]
public void CreateBuffer_returns_ten_elements()
{
    // VB 側: Dim buffer(9) As Byte → 10要素
    var buffer = BufferFactory.Create();
    Assert.Equal(10, buffer.Length);
}

C# プロジェクトでテストを実行する手順は dotnet test です。.NET 側の統合テストの組み立ては、ASP.NET Core Web APIの統合テストの記事が参考になります。

dotnet test src/Billing.Tests

任せきれない部分と、使い分け

レビュー役が見るのは、2つのファイルの比較で分かる範囲です。実行時にだけ決まる値(データベースのNULL、地域設定、ファイルの文字コード)の差は、テストでしか確かめられません。レビュー役の「差なし」は、実行しても差がないという意味ではないので、判定を鵜呑みにしません。

サブエージェントとメイン会話の使い分けは、ドキュメントの基準で整理できます。

  • 変換の修正を何度も往復する作業は、メインの会話に向く
  • 新旧ファイルの突き合わせのように、出力が長く、要約だけ欲しい作業は、サブエージェントに向く

もう一つの分岐は、規模です。.NET Framework全体を .NET 8以降へ移すような大規模な移行は、AWS Transformのようなプラグインが対象にしています。Claude CodeのAWS Transformプラグインの記事では、VB.NETを含む変換の枠組みを扱っています。レビュー役を自作するこの方法は、そこまで大がかりにせず、数プロジェクトを手元で確かめたい場面に向きます。COBOLを含む広い移行は、コードモダナイゼーションの記事に手順があります。

変換後のレビュー役を読み取り専用に絞る設計は、読み取り専用のDB分析サブエージェントの記事と同じ考え方で、書き込みの許可を与えない側に倒しています。

まとめ

VB.NETからC# への変換で追うべきは、構文ではなく、VBが暗黙に担っていた挙動です。Option StrictがOffのファイル、Dim a(n) の配列、値型へのNothing、Option Compare Text、Andの両辺評価。この5点は、コンパイルが通っても結果を変えます。

機械変換の後に、元のVBと並べて読むだけの読み取り専用サブエージェントを置き、指摘をVBの実行結果に基づくテストで確定します。レビュー役は所見を出し、確定は実行で行う、という役割の分け方が要です。

参照した一次ソース

この記事の記述は、次の一次ソースと照合しています。更新時に参照先が変わった場合は一覧も更新します。

  1. code.claude.com/docs/en/sub-agents
  2. learn.microsoft.com/en-us/dotnet/core/porting
  3. learn.microsoft.com/en-us/dotnet/visual-basic/language-reference/statements/op…
  4. learn.microsoft.com/en-us/dotnet/visual-basic/language-reference/nothing
  5. learn.microsoft.com/en-us/dotnet/visual-basic/programming-guide/language-featu…
この記事を共有:XはてブLinkedIn