Programming by superstition

Myths and half-truths around .Net and C# best-practices crop up frequently in discussion forums, with rationales ranging from utterly believable to indefensible.  I thought I would catalogue the ones I see most frequently.  I realise I am leaving myself open to ridicule by prefixing my 'corrections' with 'Truth', but someone has to make a stand :-)  Feel free to correct me.

Myth:

Always set your objects to null (or Nothing) when you're done with them.

Rationale:

The garbage collector won't be able to free an object if any another object is referencing it. 

Truth:

The garbage collector can free any object that is unreachable from any of the various heap roots.  If object A references object B, and object A is unreachable, object B can be released if it has no other references from reachable objects.

Myth:

StringBuilder.Append() is always faster than String.Concat().

Rationale:

String operations always create new string objects, whereas StringBuilder uses internal magic to avoid expensive allocations.

Truth:

Using a StringBuilder is sometimes (even usually) faster than using simple string concatenation, but there is a performance cutover point.  Various people have found this to be around the 5 - 10 concatenations mark.  The bottom line being that replacing this:

string fullName = firstName + " " + lastName;

with this:

StringBuilder builder = new StringBuilder();

builder.Append(firstName);

builder.Append(" ");

builder.Append(lastName);

string fullName = builder.ToString();

is rather pointless.  Remember that StringBuilder is itself reference type, and has the associated allocation/deallocation costs.

Myth:

Strings are passed to, and returned from, methods by-value.

Rationale:

Strings are immutable, therefore they must have value type semantics, therefore must be copied by value.

Truth:

Strings have certain value-type semantics (namely, immutability), but are otherwise heap-based reference types, and references to them can indeed be passed or copied.  Passing a string reference to or from a method does not copy the underlying string.

Myth:

Dispose() releases an object's memory.

Rationale:

Well, it's called 'Dispose' isn't it?

Truth:

Dispose() is merely a convenient place for a class' developer to place any resource clean-up code, in the hope that clients will call it.  Dispose does not free the managed memory allocated for an object.  The only thing that can do that is the garbage collector; there is no way to deterministically (or manually) release memory.

Myth:

Keeping ADO.Net connection objects open for the duration of a [Page/Control/1000-line method]'s lifetime is more efficient than repeatedly opening and closing it around each operation.

Rationale:

Connecting to a database is expensive, so try to avoid doing it too much.

Truth:

If your managed provider allows connection pooling, and if pooling is enabled (it is, by default, for the managed SQL Server provider at least), calling Close() on the connection object does not simply close the underlying connection.  It merely releases that connection back to the pool where it can be associated with another managed connection object at some time in the future.  This is a Good Thing, especially in multi-threaded environments such as ASP.Net, because physical connections are rare resources and should not be coveted.  (By the same token, calling Open() on a managed connection when a pooled physical connection is available will simply associate the former with the latter).

By keeping a managed connection in an open state, you are preventing objects in other threads from getting hold of them, leading to potential bottlenecks.

Myth:

Int32 and int are not the same thing (ditto float/Short, long/Int64, string/String, etc.).

Rationale:

They're spelled differently.

Truth:

The C# simple type keywords are interchangeable with the equivalent BCL types; they are aliases.

8 Comments

  • This is good stuff. Thanks.

  • Nice list - I have been banging on the same points, when I read code with similar constructs. Especially the setting to Null one!!

  • To be fair, there are times when explicitly nulling out a reference is absolutely the right thing to do (generally if you have a root object that's holding references unnecessarily), but most of the time it has no effect on object lifetime.



    Jim

  • "the first point about setting to null appears to matter although in very few cases"



    Yes, I didn't emphasise the "always" enough. The "always" is the superstitious part, and leads to code like this:



    void Foo()

    {

    Bar bar = new Bar();

    bar.DoSomethingCool();

    bar = null;

    }



    Jim

  • Dispose() does have another benefit. If you implement IDisposable, you can write something like

    using (Blah b = new Blah()) {

    b...



    }

    At the end of that block, compiler will put the code to call Dispose automatically. Useful when you acquire expensive resources.

  • That's a pretty entertaining list...

  • I do this, but for a different rationale - if I make some logic error then, or more likely six months down the line in maintenance, I'd like a NullReferenceException to tell me so.



    That saves me time tracking down the mistake, and the



    blah = null ;



    lines serve as comments to remind me that yes, I am really done with that object then.

  • News and pictures from the world of celebrity
    Thank you.

Comments have been disabled for this content.