VB.NETはヤバい
最近VB.NETと戯れてるんですが、C#と同じフレームワーク上なのにスゲー書きづらいことが分かりました。
煮え切らない感じが続いてるのでこのあたりでVB.NETのヤバいとこを書いてストレス解消しておきます。
たとえば
こんなクラスがあったとしましょう。
Public Class TestClass Public Delegate Sub SomeEventHandler(result As String) Public Event SomeEvent As SomeEventHandler Private _target As String Public Property Target() As String Get Return _target End Get Set(value As String) _target = value End Set End Property Public Sub New() End Sub Public Sub CallEvent() RaiseEvent SomeEvent(Me._target) End Sub End Class
クラスオブジェクト内のフィールドの値をイベントハンドラ経由で返してくれるイベントを持ったクラスです。
こいつを使う時にラムダ式でカジュアルにコールバックメソッドを追加してやります。
Module Module1 Sub Main() Dim test As TestClass = New TestClass() Dim str As String = "Test data" test.Target = str Dim callback As String = "Empty data" 'これは正常に動かない AddHandler test.SomeEvent, Function(x) callback = x test.CallEvent() Console.WriteLine(callback) '#>Empty data End Sub Private Sub MyEventHandler(sender As String) _callback = sender End Sub End Module
こうすればローカル変数callbackにTestClassのフィールドの値"Test data"がそのまま入ってくるような感じがしますが、 実際にはうまくいかず、"Empty data"が表示されてしまいます。
もしコールバックメソッドで値を代入するには、次のように記述する必要があります。
Module Module1 'プライベートフィールドを定義 Private _callback As String = "Empty Data" Sub Main() Dim test As TestClass = New TestClass() Dim str As String = "Test data" test.Target = str 'これはOK AddHandler test.SomeEvent, AddressOf MyEventHandler test.CallEvent() Console.WriteLine(_callback) '#>Test data End Sub 'コールバック関数をちゃんと定義 Private Sub MyEventHandler(sender As String) _callback = sender End Sub End Module
C#だとこういう問題は起きません。困ったさんですね。 同じフレームワークならこの辺りの挙動も同じにしてほしいんですが・・・。
ちなみにC#で書くとこんな感じになります。いいっすね。
class Program { static void Main(string[] args) { var test = new TestClass(); test.Target = "Test data"; var callback = "Empty data"; test.SomeEvent += (x) => callback = x; test.CallEvent(); Console.WriteLine(callback); //#>Test data } } class TestClass { private string _target = ""; public delegate void SomeEventHandler(string result); public event SomeEventHandler SomeEvent; public string Target { get { return _target; } set { _target = value; } } public TestClass() { } public void CallEvent() { SomeEvent(_target); } }
ここがヤバい!VB.NET
ラムダ式の構文が冗長
C#ではアロー演算子でサクっと記述できていたので結構ラムダ式好きだったんですが、VB.NETはかなり冗長だなーと思います。
たとえばEnumerableなクラスオブジェクトに対して.FirstOrDefaultメソッドを呼ぶときは
var result =Target.FirstOrDefault(x=> x.value == anyObj.Text).Key
みたいにいい感じがするんですが、VB.NETでは
Dim result as String = Tareget.FirstOrDefault(function(x) x.value = anyObj.Text).Key
はい・・・。
まずFunction(x)ってなんなの。めっちゃ「はーい!僕が匿名メソッドでーす!」みたいな感じ丸出しでダサい。(完全に個人的な感想)
あとアロー演算子が不要なのが、かえって可読性を下げていると思います。
そんでもって挙動がC#と違う?っぽいのが結構キてます。渡し方によってはラムダ式でも同じ挙動にできるのか正直わかってないですけど。
あとDimって書かせてから変数名書いた後に「as ClassName」ってのも冗長で好きじゃないですね。
イベントハンドラの構文が分かりづらい
AddHandler testClass.SomeEvent, AddressOf MyEventHandler
とか、
RaiseEvent SomeEvent(_target)
とか。
VB.NETが生まれた背景を考えると仕方ないんでしょうけど、さすがにAddressOf演算子を使わないとイベントハンドラ登録できないって結構ヒドいなと思います。
シンタックスシュガーぐらい用意してもいいんじゃないんでしょうかね。
そもそも.NET Frameworkってアンセーフコードでない限りポインタ演算子をサポートしないはずでは?構文にポインタの概念が漏れ出しまくってるけど大丈夫?
おわりに
ストレスが解消されたのでよかったです。でもVB.NETはしばらく触りたくないですね。