More C# Oddities

As a Delphi Developer learning C# there are a few very odd things to deal with:

  • The  final  line of a method  must be terminated  with a  ;
  • Why  does a  switch  statement require  a  break at  every stage?  There presence is enforced by the compiler – why bother?
  • Why can’t you call a class method on an instance?
  • Where are the meta classes?

Microsoft and Installers

Microsoft are not very good at writing installers.
If you try to install MSDE on a machine that is not a print or file server then it will take a long time to install, fail silently and fully roll back.
MSI is a ridiculously complex piece of technology. It fails to acheive the basics of informing the user what is wrong when things go wrong.

Visual Studion.NET 2003 has a “great” tool for producing msi installers. It is almost an example in how to be counter-intuitive. For example in order to install a .NET service you need to add the two installer components to the service, add a custom task and then add the service (that is already part of the installation) to the four events (install, &c). Failure to do this can have interesting effects; it is possible to install a service, change the installer so that it is no longer recognised for uninstall and result in multiple reboots plus deletion of parts of the registry to uninstall a service. Why can’t you force the removal of a service using the Service manager? This could easily be locked down to admins only.

Why does .NET make configuring COM servers and services so difficult. Delphi builds registration into the appropriate code so that they can self register/unregister. This makes so much sense – you can never be left with an exe that you can’t uninstall.

want and nant

I have been using the want build tool to manage a resonable size delphi project.
However I have taken over support of some related C# code.
I am investigating porting the delphi specific tasks (delphi compiler, the resource compiler and dunit) to nant. So far the hardest part has been getting each of them to build in the IDE.
Once this is done I will be able to create a unified build tool.

C# Constructors

The C# constructor syntax is odd.

MyClass : MyAncestor
{
    public MyClass(int Foo) : base(Foo + 1)
    {
       // implementation ommited
    }
}

You can’t directly call the ancestor.
However you are allowed to make manipulations on the data.
You can even invoke static methods on the class that you are creating:

MyClass : MyAncestor
{
    public MyClass(int Foo) : base(Bar(Foo))
    {
       // implementation ommited
    }

    static int Bar(int Foo)
    {
       return Foo + 1
    }
}

This does allow a certain amount of flexibility.
However since static methods cannot be virtual you can’t quite reach the flexibility of Delphi.
Delphi would allow a virtual method to be called that can set values before the inherited constructor is called. This can be very useful in some situations.For example if the ancestor is creating a font you could have a descendant choose whether the font is bold.

More usability issues

The .NET TextBox class when set to multi-line is a very weak control compared to Delphi’s rich TMemo control. TMemo exposes a Lines property to which a line of text can be simply added r individual lines manipulated. I need to look at the TStringList for C# to see if I can use it to create a fully featured TMemo for .NET.

            textBox2multiline.Text += System.Environment.NewLine + “This is a test”;

is far more code (and far less obvious) than:
 
             memo1.lines.Add(‘This is a test’);

In addition when you rename a delphi control if the text property matches the control then the text property changes as well. I wonder if the designer could be extended that far? This makes editing controls much easier – first you rename them and then you customise that into the correct text. This is far more efficient.

Useability issues

One of the reasons why Borland products tend to score above the microsoft equivalents is in the area of  small usability touches.

The .NET Framework has a LinkLabel control. The purpose of this is to allow hyperlinks &c.
However there is no desgner for this. You have to add the associated links in code.
While this is flexible it is more difficult than necessary to use for the simple case. Borland would have implemented the designer here.

Borland’s big problem has been marketing and sales.  Even when they have a superior  product they  cannot get the market to accept it.  Of late they seem to be diversifying into earlier stages of the lifecycle – requirements (CaliberRM), design (Together and Bold) and configuration/planning (StarTeam). It is difficult to complete against the Microsoft Universal licence (allowing access to almost all the development tools for a fixed annual fee) – Microsoft make their money off of the server products that the customers require. Borland could launch a product as a Visual Studio extender – adding in the missing property editors.

More Missing Stuff

Moving from the Delphi IDE to Visual Studio can be very frustrating.
While VS.NET is a real combine harvester in that it can perform a wider range of editing
than the Delphi IDE it seems to be lacking in some basic smarts that were in Delphi 1 ten years ago.

In Delphi when you rename the main form the equivalent of Application.Run is automatically updated. This may be a small thing but unless you want every app to have Form1 as it’s main form this is going to get rather old very quickly.

In Delphi when you leave an event handler empty (no code or comments) and build then the IDE removes it from the event handlers of associated objects. When you rename a control that has an event handler named after it the event is renamed and all of the IDE linked references are updated. If you have coded against it you need to fix these up yourself.

These are small things, but do grate.

Why so brittle?

C# has inherited a brittleness from the Visual C++ world.

By default an unhandled exception in any application will kill an application and return an exception trace even in a windows form.

In Delphi in a forms application the exception shows as a message box.

The assumption in Visual C++ and then C# is that an unhandled exception could result in data corruption so you must shut down now. The assumption in delphi is that some error has occoured.

It is possible to add simple code to emulate the Delphi behavior

// Add the following to your uses clause:
using System.Threading;

//In your main method before run implement the following

Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(new CustomExceptionHandler().OnThreadException);

// Here is the exception handler (in production code use something more elegant, but for development this is fine:

        // Creates a class to handle the exception event.
        internal class CustomExceptionHandler
        {
 
            //Handles the exception event
            public void OnThreadException(object sender, ThreadExceptionEventArgs t)
            {
                DialogResult result = DialogResult.Cancel;
                try
                {
                    result = this.ShowThreadExceptionDialog(t.Exception);
                }
                catch
                {
                    try
                    {
                        MessageBox.Show(“Fatal Error”, “Fatal Error”,
                            MessageBoxButtons.AbortRetryIgnore, MessageBoxIcon.Stop);
                    }
                    finally
                    {
                        Application.Exit();
                    }
                }
 
                // Exits the program when the user clicks Abort.
                if (result == DialogResult.Abort)
                    Application.Exit();
            }
 
            // Creates the error message and display it.
            private DialogResult ShowThreadExceptionDialog(Exception e)
            {
                string errorMsg = “An error occurred please contact the adminstrator ” +
                    “with the following information: “;
                errorMsg = errorMsg + e.Message + ” Stack Trace: ” + e.StackTrace;
                return MessageBox.Show(errorMsg, “Application Error”,
                    MessageBoxButtons.AbortRetryIgnore, MessageBoxIcon.Stop);
            }
        }

    }

However this should be the default behaviour.

Where are C#'s meta-classes?

In Delphi you can define a meta class and pass classes into methods.

TFoo = class(TObject);

TFooClass = class of TFoo;

function MakeFoo( aFooClass : TFooClass ) : TFoo;
begin
    result := aFooClass.Create();
end;

This allows very generic code where you can get away with just passing in a class name.
I use this heavily in Delphi as part of a test framework (the meta class represents test data).

I think that this can be done in C# using reflection but there should be a cleaner method.