What I Learned Porting .NETpad to C# (Premium)

I decided to port .NETpad from Visual Basic to C# in order to get up to speed on the latter language as quickly as possible. My plan is to use the more sophisticated C# language in at least the next few projects, and I didn’t want to have to worry too much about learning the language at the same time as learning a new framework.

I’ve mentioned this work a few times, most recently in What I’ve Learned About C#, Visual Basic, Windows Forms, XAML, and WPF (Premium). But as I write this, my C# porting effort is just about done: I’m still using Windows Forms and the .NET Framework, so all I really needed to do was duplicate the .NETpad user interface with the Visual Studio designer and then rewrite my event handlers and custom methods in the new language. It was time-consuming and occasionally difficult, in part because of obscure language differences and in part because Visual Studio treats C# very differently than it does VB.

Let’s talk about the language differences first.

As you may know, C# is a far more sophisticated language than VB, and it’s more syntactically similar to Java and other C-like (or “curly braces”) languages. On the flipside, VB is simpler, easier to read (especially for beginners), and thus is easier to learn as well. And for their use in Windows Forms applications, the two languages are essentially identical, from a functional perspective. (I suspect the situation is similar in Windows Presentation Foundation (WPF) and other newer frameworks, but we’ll find out soon enough.) That’s why I used VB for this first project.

But because C# is the lingua franca of the Microsoft development world, one of the issues with using VB—and this undercuts my claim above that VB is “easier,” in some ways—is that most of Microsoft’s documentation only provides examples in C#. So as I was making .NETpad, I often had to translate C# into VB when referencing Microsoft’s documentation. It was worth doing and instructional in its own way. But this will be a hurdle for anyone that chooses VB today.

(And in recent years, VB and C# development, which had previously occurred in lockstep with each other, has forked, with C# typically getting new features first, or VB not getting some new features at all. This hasn’t had any major ramifications yet, but it adds to the notion that VB has sadly become something of a second-class language.)

Anyway. Let me provide a few examples.

Most simplistically, you’ll be dealing with curly braces (“{“ and “}”) to demark code blocks and semi-colons (“;”) to demark the end of each line of code when you use C#. Consider the following simple If-Then-Else block in VB:

If TextBox1.WordWrap = True Then
    TextBox1.WordWrap = False
Else
    TextBox1.WordWrap = True
End If

In C#, that same code block looks very similar:

if (textBox1.WordWrap == true)
{
    textBox1.WordWrap = false;            
}
else
{
    textBox1.WordWrap = true;
}

There are actually several differences, despite the similarities. The capitalization of keywords is different: VB uses capitalization, while all keywords in C# are lowercase. C# uses curly braces and semi-colons. C# uses == instead of = to check for equality, but it uses = for assigning a value (as in textBox1.WordWrap = false;). The if block in C# places the comparison check inside of parenthesis, where VB does not.

I had expected VB to let me use code like Form1.Text = “some text” to assign some value to a property of the main form window. But Visual Studio doesn’t allow it, and it will flag the code with an error that reads, “’Form1’ cannot refer to itself through its default instance.” Fortunately, it provides the solution, too: “Use ‘Me’ instead. In other words, the code Me.Text = “some text” would work fine. Me is a VB keyword that’s used to “refer to the specific instance of a class or structure in which the code is currently executing,” according to Microsoft’s documentation.

But Me doesn’t exist in C#. If you try to write a line of code that reads, Me.Text = “some text”;, you will discover that “the name ‘Me’ does not exist in this context.” Here, Visual Studio does not provide the answer. (In fact, its suggested fixes are useless) So you have to Google the answer: The equivalent to Me in C# is, as it is in some other C-like languages, this. So the following code would work:

this.Text = "some text";

As it turns out, however, both Me (in VB) and this (in C#) are superfluous. I kept Me in my VB code listings for clarity’s sake, but as I moved to C#, I started to adopt its more modern and terse style. So that previous line of code would really read as:

Text = "some text";

(And in VB it would read as Text = “some text”).

In .NETpad, we often display some dialog—Font, Color, Open, Save/Save As, plus various Message Boxes and Input Boxes—and perform some action only when the user has chosen OK (or its equivalent). For example, if the user opens the Font dialog to select a new font but then clicks Cancel (or types ESC), then there’s no reason to do anything. So I always combined the opening of that dialog (via ShowDialog(), typically) with a check of the return value. If the return value is “OK,” then some code occurs.

In VB, that typically takes the following form:

If FontDialog1.ShowDialog = DialogResult.OK Then
    ' Do something
End If

I like this because it’s concise, and I don’t have to explicitly create a new object of type DialogResult to make it happen.

In C#, however, I never figured out an elegant way to do that all in one line. And so the same code in C# looks like this:

DialogResult Result = fontDialog1.ShowDialog();
if (Result == DialogResult.OK)
{
    // Do something
}

First, you create a new object of type DialogResult and then use that to store the return value of the Font dialog. Then you check that result and, if it’s “OK,” you do something.

There are esoteric differences. When I was trying to figure out printing and finally decided to translate Charles Petzold’s C# code from Programming Microsoft Windows with C# into VB, I ran into this interesting line of code:

StrFmt.FormatFlags |= StringFormatFlags.NoWrap;

And that operator, |=, was new to me, so I had to look it up. As it turns out, only | is an operator, which stands for Logical OR, and Petzold had combined it with the = assignment to create a terser line of code. He could have used this longer form (where | reads as “OR”) instead:

StrFmt.FormatFlags = StrFmt.FormatFlags | StringFormatFlags.NoWrap;

So, translating that into VB was actually pretty straightforward:

StrFmt.FormatFlags = StrFmt.FormatFlags Or StringFormatFlags.NoWrap

There was another stumbling block in Petzold’s printing code, though it looked straightforward at first:

while ((PageNumber < StartPage) && (PrintText.Length > 0))

I took this to mean, “while the page number is less than the start page AND the length of the print text is greater than zero, do something.” But && does not mean AND. Instead, it is a “conditional logical AND” operator. Or what VB calls AndAlso. This was new to me, but that line in VB reads like so:

While PageNumber < StartPage AndAlso PrintText.Length > 0

Also, it was kind of interesting to convert his C# code into VB and then go and convert my VB code back to C# for the C# version of .NETpad. Yes, that is the way I did it, and it works fine.

Ultimately, what fascinated me most about this process was how strict the C# compiler is, by default, compared to the VB compiler. Visual Studio is a sea of green squiggles and gray dots, each indicating something that it finds offensive enough to warn you about. These warnings won’t stop the application from compiling or running. But while they are a bit annoying, they’ve also pointed me in some interesting directions.

The most obvious is the need to make the application location-aware, and the most obvious way to do that is to avoid literal strings. For example, consider the following basic line of code:

MessageBox.Show("The line number is beyond the total number of lines", "Go to line");

In Visual Studio, both of those strings (“The line number is beyond the total number of lines” and “Go to line”) have a green squiggle under them, indicating a warning. That warning tells me that I should not use literal strings, which are essentially hard-coded in the application, but should instead use a resource table instead. That way, I could read in all the string values needed by the app at runtime and use the correct resources based on the locale configured in Windows. If I provided French language resources, for example, I could load them when the local was France (or whatever).

I haven’t made that change yet, but I would like to, and that’s one of my major remaining goals for this project. (And Visual Studio offers similar warnings for other values, like numbers, that can vary by locale.)

Other warnings are a bit more vexing. When I encounter an exception, I just display a Message Box that displays the exception text. But Visual Studio doesn’t like that when I’m using C#. Instead, it would like me to modify the catch block to check for specific exception types. That’s vague enough that the “Show potential fixes” option it provides is quite welcome. But the suggestions just explain how I can suppress that warning. I’d rather know how to make it right.

C# also has ideas about how things should be named. If you’re familiar with the VB version of .NETpad, you may know that I just use what’s called camel case for object names, and that each name begins with a capital letter. So UI elements (TextBox1), event handlers (StatusBarToolStripMenuItem_Click), properties (TextHasChanged), variables (Count), and everything else is named that way.

C# is OK with camel case, but it really wants the first letter to be lowercase. So if you add a new textbox to a C# app, it will be named textBox1, not TextBox1. That’s fine. But the event handler names that Visual Studio generates are flagged with warnings.

For example, I’m using a RichTextBox in this version of the application (instead of a TextBox), and I let it name the thing as richTextBox1. So when Visual Studio generated its TextChanged event handler, it was naturally called richTextBox1_TextChanged. And then that was flagged by Visual Studio because it’s a naming rule violation. “These words must begin with upper-case characters,” I’m told. In other words, Visual Studio wants this event handler to be named RichTextBox1_TextChanged. Even though it named the event handler incorrectly in the first place.

Oddly, it’s not weird about it if I decide to name properties or variables with a beginning capital letter.

There are many other differences, but these examples speak to the type of things you’ll see as you move between VB and C# using Windows Forms and the .NET Framework. I suspect there will be further differences as I move into other frameworks, starting with WPF. And perhaps again when I shift into .NET Core. But with this experience under my belt, I’m hoping that starting fresh with C# for the next project will be a bit easier than it might have been otherwise.

If you’re interested in the code for the C# version of .NETpad, I can post that on the site somehow. I just need to finish up a few features and clean up the About Box. The rest of it is pretty much complete.

Gain unlimited access to Premium articles.

With technology shaping our everyday lives, how could we not dig deeper?

Thurrott Premium delivers an honest and thorough perspective about the technologies we use and rely on everyday. Discover deeper content as a Premium member.

Tagged with

Share post

Thurrott