htsign's blog

ノンジャンルで書くつもりだけど技術系が多いんじゃないかと思います

.NET Framework における System.String について

今年に入って初めて .NET Framework にまともに触れるようになってきたのでまだまだ勉強中です。
趣味で触るのはC#、仕事で触るのはVB.NETって感じです。

さて、だいたいどの解説サイトを見ても「C#VB.NETもできることは同じ」というような解釈になってます。
ただ、System.Stringが言語によって扱いが異なる気がしています。

あるとき、VB.NETNullable(Of String)と書いたときに静的エラーが出力されました。
妙だと思い調べてみると、System.Stringは参照型であるというのです。

基本的な型のうち int, double, byte, char などは値型ですが、
string は「値型のように振る舞う参照型」であるというような記述を見ました。

参照型であるということは null を代入できるのか。
と思い、以下のコードを書きました。

C#
public class Program
{
    public static void Main(string[] args)
    {
        string string1 = null;
        string string2 = "";
        string string3 = string.Empty;

        Console.WriteLine("1:{0}", string1 ?? "string1 is null");
        Console.WriteLine("2:{0}", string2 ?? "string2 is null");
        Console.WriteLine("3:{0}", string3 ?? "string3 is null");

        Console.WriteLine(string1 == string2); // null         == ""
        Console.WriteLine(string2 == string3); // ""           == string.Empty
        Console.WriteLine(string3 == string1); // string.Empty == null
    }
}
VB.NET
Public Module Program
    Public Sub Main(args() As string)
        Dim string1 As String = Nothing
        Dim string2 As String = ""
        Dim string3 As String = String.Empty
        
        Console.WriteLine("1:{0}", If(string1, "string1 is Nothing"))
        Console.WriteLine("2:{0}", If(string2, "string2 is Nothing"))
        Console.WriteLine("3:{0}", If(string3, "string3 is Nothing"))
        
        Console.WriteLine(string1 = string2) ' Nothing      = ""
        Console.WriteLine(string2 = string3) ' ""           = String.Empty
        Console.WriteLine(string3 = string1) ' String.Empty = Nothing
    End Sub
End Module

動作デモ*1

C#     : http://rextester.com/ELTMU58022
VB.NET : http://rextester.com/IRCW50181

と、ここまで来て二つの言語間で結果が違ったことに気づきました。

これ、 ""String.Emptyエイリアスの関係なので言うまでもなく同じものです。
ですから、比較したときにtrueになるのは当然だと思います。
でも、

string string1 = null;
string string2 = "";
Console.WriteLine(string1 == string2); // ==> false
Dim string1 As String = Nothing
Dim string2 As String = ""
Console.WriteLine(string1 = string2) ' ==> True

なのです。
VB.NETではデフォルトでOption Strict Offであるため暗黙の型変換が行われたのかと思い、Option Strict Onを記述するも変わらず。

ちなみに、

Dim string1 As String = Nothing
Dim string2 As String = ""
Console.WriteLine(string2.Equals(string1)) ' ==> False

でした。

この挙動について、このエントリを書いている途中まではSystem.Stringの特殊性によるものかと思っていましたが、書いている途中でそれぞれの言語の等価演算子の振る舞いの違いによるものかも?ともちょっと思っています。
どうなんですかね、これ。

何とも尻切れトンボ感あるエントリになってしまいましたが、この辺で。

追記 (2014/11/11 1:21)

どうやら、やはり等価演算子自体が違う振る舞いをするようです。

*1:rextester.comは鯖が落ちていることが稀によくある