Casts using “as” (Pitfalls and Best Practices to Prevent Them #5)

Well – “as” is faster to type than a “real” cast using two brackets and has the same result. Really?

C# provides several ways to cast one type to another one. The two used in most cases are the “([Targettype]) [Variable]” and the “[Variable] as [Targettype]” notations. Many developers see them as equivalents, some even prefer “as” because it does not throw an exception when the cast fails.

Example

Let’s say we have a variable called obj of type Object and we want to cast it to an IFoo so we can call IFoo.Bar:

object obj;
//...
(obj as IFoo).Bar();

Read the rest of this entry »

Pitfalls and Best Practices to prevent them #4 – Object Finalizers

Let’s help the .NET Garbage Collector! Why this often backfires…

You know that the .NET Framework comes with a Garbage Collector to tidy up unreferenced objects. And you also know that there are so called “Finalizers” (sometimes also called “Destructors”) which are executed before an object’s memory is definitely deallocated.

Examples

Some people may think: “Hey – let’s help the Garbage Collector a little bit” and write code like that (Note: The console output is for a later example only):

Read the rest of this entry »

Pitfalls and Best Practices to prevent them #3: this and base

“I use base to make clear that I am calling a inherited member” – why you shouldn’t.

You all know them: The keywords this and base.

Did you ever think about which of them you should use when you can use both?

Read the rest of this entry »

Pitfalls and Best Practices to prevent them #2: Operator priority

Example

class Program
{
    static void Main(string[] args)
    {
        Foo foo = new Foo();
        foo.Test = "Baz";

        foo.Bar(null);
    }
}

public sealed class Foo
{
    public string Test
    {
        get;
        set;
    }

    public void Bar(Foo other)
    {
        this.Test += "Value:" + other == null ? "<null>" : other.Test;
    }
}

What does it do?

The method Bar contains an expression using the tertiary operator to handle the case that other is null.

In this case “<null>” is appended instead of the value of other.Test.

However, this is only what the code should do. In fact, there occurs a NullReferenceException.

Doku says

C# Language Specification (7.2.1: Operator precedence and associativity):

The following table summarizes all operators in order of precedence from highest to lowest:

Section Category Operators
7.5 Primary x.y f(x) a[x] x++ x– new typeof default checked unchecked delegate
7.6 Unary + – ! ~ ++x –x (T)x
7.7 Multiplicative * / %
7.7 Additive + –
7.8 Shift << >>
7.9 Relational and type testing < > <= >= is as
7.9 Equality == !=
7.10 Logical AND &
7.10 Logical XOR ^
7.10 Logical OR |
7.11 Conditional AND &&
7.11 Conditional OR ||
7.12 Null coalescing ??
7.13 Conditional ?:
7.16, 7.14 Assignment and lambda expression = *= /= %= += -= <<= >>= &= ^= |= =>

 

Problem

I already mentioned: There occurs a NullReferenceException.

Let’s take a closer look to the problematic line:

this.Test += "Value:" + other == null ? "<null>" : other.Test;

As the += operator has a lower precedence than the others, we can say: The following part is executed before the assignment:

"Value:" + other == null ? "<null>" : other.Test;

What about this part now? Well, as the +-operator has a higher precedence than the ?:-operator, we are now able to write what the compiler actually does in another way:

string temp = "Value:" + other; //Will always be "Value:ConsoleApplication1.Foo"
temp = temp == null ? "<null>" : other.Test; //As temp is never null, temp will be other.Test
this.Test += temp;

You should see the problem in the second line now: other.Test is accessed irrespective of its “nullstate”.

How to solve?

As always (:-)) there is a simple solution: Make clear what you want by using brackets:

this.Test += "Value:" + (other == null ? "<null>" : other.Test);

The code not only gets “right” now, it’s also easier to understand.

Generalization / Best Practice:

In (complex) statements, do not hesitate to use brackets; better “safe than sorry”. They make the code clearer and prevent errors originating in misjudged operator precedence. Two very important cases are the ?:-operator and all logical operators.

DotNetKicks Image
Posted in Pitfalls. Tags: , , . Comments Off on Pitfalls and Best Practices to prevent them #2: Operator priority

Pitfalls and Best Practices to prevent them #1: Order of the elements when iterating through a collection using foreach

Example

List<string> list = //Fill it;
//...
int index = 0;
foreach (string s in list)
    Console.WriteLine("Item \"{0}\" - Index: {1}", s, index++);

What does it do?

The example is kept quite simple: A generic List<string> gets filled with some items (—> Comment).

Later, all items in it and their indices are written to the Console.

Note: The foreach loop internally uses IEnumerable.GetEnumerator / IEnumerable<T>.GetEnumerator.

Doku says

MSDN (IEnumerator.GetEnumerator)

Initially, the enumerator is positioned before the first element in the collection. […] Therefore, you must call the MoveNext method to advance the enumerator to the first element of the collection before reading the value of Current.

[…] MoveNext sets Current to the next element.

If MoveNext passes the end of the collection, the enumerator is positioned after the last element in the collection and MoveNext returns false. […]

C# Language Specification (8.8.4: The foreach statement)

The order in which foreach traverses the elements of an array, is as follows: For single-dimensional arrays elements are traversed in increasing index order, starting with index 0 and ending with index Length – 1. For multi-dimensional arrays, elements are traversed such that the indices of the rightmost dimension are increased first, then the next left dimension, and so on to the left.

Problem

Well, it’s a question of interpretation: Does MoveNext set to the next element in the collection or only to the next element (regardless to its position in the collection)? Only the behavior when dealing with arrays is specified unambiguously.

There could be a class implementing (for whatever the reason) GetEnumerator like follows:

private List<string> innerList;
//...
public IEnumerator GetEnumerator()
{
    for (int i = this.innerList.Count - 1; i >= 0; i--)
        yield return this.innerList[i];
}

Using this code together with the first one causes significant problems: The displayed indices are wrong now.

And there are classes that behave different; Class" href="http://msdn.microsoft.com/en-us/library/xfhwa508.aspx" target=_blank>Dictionary<,> is a prime example:

For purposes of enumeration, each item in the dictionary is treated as a KeyValuePair<TKey, TValue> structure representing a value and its key. The order in which the items are returned is undefined.

How to solve?

Don’t use foreach loops when you need the index of an element. (And also don’t use IndexOf in a foreach loop – this, however, has performance reasons).

Use a plain old for-loop instead 😉

List<string> list = //Fill it;
//...
int index = 0;
for (int index = 0; index < list.Count; index++)
{
    string s = list[index]; //Of course you don't have to introduce a variable
    Console.WriteLine("Item \"{0}\" - Index: {1}", s, index++);
}

However, this is no solution if you are using a dictionary; thanks to SeeQuark for informing me about this. In this case, if you really need a well-definied order, you’ll have to add an index to the elements in it.

Generalization / Best Practise:

Do not rely on the order elements will be returned by an iterator. As the foreach-loop uses one, the same applies to it. Foreach-loops using a counter variable in order to determine the index of each element should be replaced with for-loops.

DotNetKicks Image

New column: Pitfalls and Best Practices to prevent them

As you maybe know I am an active member of myCSharp.de.

Reading through the postings there (and answering them, of course ;-)) I sometimes think that there definitely have to be other people with the same problem without knowing it.

That means those problems are really hidden logical mistakes which are mainly caused by inaccurate usage of types or language features. In most cases they won’t catch somebody’s eye as their impacts only come to light under special (unfortunate) circumstances. Then, however, they are really difficult to find. You could say: They are no real bugs but they may cause bugs.

So I decided to start this new column which I’ll try to keep alive as long as this blog will exist. I hope, you’ll like it. 🙂

DotNetKicks Image
Posted in Pitfalls. Tags: , , , . Comments Off on New column: Pitfalls and Best Practices to prevent them