Praktyczne różnice pomiędzy C# a Vb.Net

Od około półtora roku pracuję w projekcie, który początkowo był napisany w Vb.Net, ale teraz nowszy kod jest tworzony w C#. To świetny przykład tego, jak jeden projekt można napisać w dwóch językach, a kod w Vb.Net może odwoływać się do C# i na odwrót.

Vb.Net i C# są bardzo podobne i są kompilowane do tego samego języka pośredniego, ale niektóre różnice są bardziej zaskakujące niż inne.

Proste różnice

Zacznijmy od rzeczy oczywistych. Vb.Net używa prostego języka angielskiego w swojej składni, podczas gdy C# używa składni opartej na C. Spójrzmy na przykład.

    private string ReplaceAnd(string s)
    {
        if (s != null && s.Contains(":"))
            return s.Replace(":", "?");

        return s;
    }

A teraz ten sam przykład w Vb.Net:

    Private Function ReplaceAnd(s As String) As String
        If s IsNot Nothing And s.Contains(":") Then
            Return s.Replace(":", "?")
        End If

        Return s
    End Function

Przyzwyczajenie się do deklarowania typów za pomocą słowa kluczowego As zajęło mi trochę czasu. Także If potrzebuje słowa Then, ale to są rzeczy, które piszesz raz lub dwa razy i staje się to nawykiem.

Moim zdaniem największe zmiany przy porównaniu C # z Vb.Net to:

  • nie używamy nawiasów do bloków kodu
  • nie ma potrzeby umieszczania średników na końcu instrukcji
  • nazwy zmiennych nie uwzględniają wielkości liter
  • i kilka innych 😃

&& vs And vs AndAlso

Wszystkie te proste różnice to tylko różnice w składni języka, ale zasadniczo kod pozostaje taki sam. Jednym z moich największych błędów podczas pisania kodu Vb.Net było użycie operatora And jako && z C#. Chodzi o to, że te dwa operatory nie są równoznaczne.

Spójrzmy na przykład. Użyję dwóch metod, które sprawdzają wartość null w instrukcji If i dokonają podmiany ciągu znaków.

    Private Function ReplaceAndAlso(s As String) As String
        If s IsNot Nothing AndAlso s.Contains(":") Then
            Return s.Replace(":", "?")
        End If

        Return s
    End Function

    Private Function ReplaceAnd(s As String) As String
        If s IsNot Nothing And s.Contains(":") Then
            Return s.Replace(":", "?")
        End If

        Return s
    End Function

Różnica pomiędzy And i AndAlso jest następująca:

  • And sprawdzi warunek po prawej stronie, nawet jeśli warunek po lewej stronie jest fałszywy
  • AndAlso nie sprawdzi warunku po prawej stronie, jeśli ten po lewej jest fałszywy

Aby to zobrazować, napisałem testy jednostkowe:

    <TestCase("abc:d", "abc?d")>
    <TestCase(Nothing, Nothing)>
    Public Sub AndAlsoTest(toReplace As String, expected As String)
        ReplaceAndAlso(toReplace).Should().Be(expected)
    End Sub

    <TestCase("abc:d", "abc?d")>
    <TestCase(Nothing, Nothing)>
    Public Sub AndTest(toReplace As String, expected As String)
        ReplaceAnd(toReplace).Should().Be(expected)
    End Sub

A rezultaty są następujące:

AndTest kończy się niepowodzeniem, ponieważ operator Andsprawdza zarówno warunek po lewej, jak i po prawej stronie, co powoduje wyjątek NullReferenceException. Więc jeśli chcesz sprawdzić wartość null w instrukcji If i zrobić coś innego, po prostu użyj AndAlso.

Wymuszenie przekazania zmiennej przez wartość

Może nie jest to duża różnica, ale byłem zaskoczony, że da się to zrobić.

Przyjrzyjmy się prostemu kodowi i dwóm testom:

    <Test>
    Public Sub AddTest()
        Dim a As Integer = 5

        Dim result = Add(a)
        a.Should().Be(6)
        result.Should().Be(6)
    End Sub

    <Test>
    Public Sub AddByValueTest()
        Dim a As Integer = 5

        Dim result = Add((a))
        a.Should().Be(5)
        result.Should().Be(6)
    End Sub

    Public Function Add(ByRef x As Integer) As Integer
        x = x + 1
        Return x
    End Function

Mamy prostą metodę Add, w której zwiększamy podaną wartość o 1. Przekazujemy tę zmienną przez referencję, więc również należy ją zmienić.

Zauważ, że w AddByValueTest przekazujemy (a) i w ten sposób możemy przekazać zmienną przez wartość. Zauważ, że działa to tylko dla typów wartościowych.

A wyniki dowodzą, że tak naprawdę działa:

Zamiana enum na string

Ta różnica mnie zaskoczyła, kiedy ją zobaczyłem i była to ostateczna motywacja do napisania tego postu. Robiłem refaktoryzację wokół Vb.Net z konwersją enum-ów, a mój kolega przeglądał zadanie i powiedział.

– Hej, fajna refaktoryzacja, ale obawiam się, że może nie zadziałać. – powiedział kolega.

– Naprawdę? Uruchomiłem ten kod i działał poprawnie. – Powiedziałem.

– Lepiej sprawdź to jeszcze raz, dla pewności napisałem nawet test jednostkowy. – powiedział kolega.

Rzućmy okiem na ten test. Konwertuję enum na ciąg znaków.

    public enum ProfileType
    {
        Person = 1,
        Company = 2
    }

    [Test]
    public void ConvertEnumTest()
    {
        Convert.ToString(ProfileType.Company).Should().Be("2");
    }

A kiedy go uruchomisz, zawodzi, mój kolega miał rację. 😲

Jednak byłem podejrzliwy i kod, który napisałem był w Vb.Net, a nie w C#, więc napisałem kolejny test. Ale tym razem w Vb.Net.

    <Test>
    Public Sub ConvertEnumTest()

        Convert.ToString(ProfileType.Company).Should().Be("2")

    End Sub

I wiesz co? Przechodzi!

Więc mój oryginalny kod był poprawny. Jednak Convert.ToString() na enum działa inaczej w Vb.Net i C#.

Summary

Praca z Vb.Net brzmi jak powrót do średniowiecza, ale w rzeczywistości dość szybko przyzwyczaiłem się do składni Visual Basic. Możliwości obu są bardzo podobne, ponieważ pod spodem nadal jest ten sam kod, ale C# wydaje mi się nieco bardziej zwięzły i intuicyjny. Może dlatego, że w szkole wolałem C++ od Pascala 😁

Mam nadzieję, że post Ci się podobał, miłego dnia! 😊

Leave a Reply

Your email address will not be published. Required fields are marked *