Login | Register   
Twitter
RSS Feed
Download our iPhone app
TODAY'S HEADLINES  |   ARTICLE ARCHIVE  |   FORUMS  |   TIP BANK
Browse DevX
Sign up for e-mail newsletters from DevX


advertisement
 

C# 3.0 Syntax Additions—Design Guidelines : Page 2

These guidelines will help you understand new additions to C# 3.0 syntax and avoid some of the pitfalls you can encounter when using them.


advertisement
Anonymous Types
Anonymous types let you instantiate a class without having to declare it. This, of course, requires that you use the var keyword because you don't have a name for your class. For example:

var person = new { Name = "Peter", Age=4};

As you might have inferred by the syntax, there's no way to define a method on an anonymous type, which truly restricts its usefulness in real-world scenarios. Because you're not really declaring a type, you can't add attributes to the type; so, you can't make it serializable, either.

Anonymous types are also immutable. This essentially means that when you instantiate an anonymous type you're not declaring fields, but read-only properties; those properties have only a get, not a set.

In sum, anonymous types are really only useful for very short-lived data.

Recommendations:
  • Avoid anonymous types for long-lived data.
Implicitly Typed Local Variables
Another controversial addition in C# is implicitly typed local variables, aka var. Naming aside (having the name var greatly reduces the possibility that it will collide with a type in the wild), var was introduced largely because the type returned by a LINQ query could contain an anonymous type and therefore may not have a human-readable name.

The type resulting from a LINQ statement can also be very complex. When not dealing with anonymous types, the designer may infer the resulting type and manually type it in for the declaration; but database queries are often very mutable, requiring the designer to re-infer the type whenever the query changes.

Apart from their uses with LINQ statements, var tends to make source code both less readable and unsearchable. For example, if you declare a class (MyClass) and use var whenever you instantiate this class, you have no way to perform a code search for "MyClass" to find out where it's used unless the right-hand-side of the expression being assigned to the var variable uses the class name.

Most expressions in C# result in an expected type; but some do not. Binary operations and integer types are a good example. Integer binary operations do not support operations where one side is signed and the other side is unsigned. The following code generates an error:

uint unsignedNumber = 42; int signedNumber = 10; int result = unsignedNumber * signedNumber;

The error message that results from running the preceding code is a little misleading: "Cannot implicitly convert type 'long' to 'int'." The error mentions the long type because the compiler performs an implicit conversion from uint to long. This is what the compiler has done:



int result = (long)unsignedNumber * signedNumber

That's one way of performing a binary operation on a signed and unsigned integer; but since result must be an int, the compiler can't implicitly convert the long to an int, so it generates a warning.

If you use var in place of int for the result, the error goes away:

var result = unsignedNumber * signedNumber;

That works, but the result is neither a uint nor an int—it's a long. And it's not a ulong, either.

Another, less subtle example has to do with method return types. If you use var with results of a method, the code that uses that variable is now coupled to the implementation of that method. If you later change the method's return type, you also change the effect of the code that uses that variable. For example:

private int GetWeight ( ) { return 17; } private decimal GetQuantity ( ) { return 11; } String Method() { var quantity = GetQuantity (); decimal result = GetWeight() * quantity / 4; Trace.WriteLine("result:" + result); return "result: " + result; }

When you run the preceding code, the result is:

result:46.75

Now, if you modify GetQuantity to return an int instead:

static int GetQuantity ( ) { return 11; }

…you'll see this result:

total:46

Although still strongly typed, use of implicitly typed local variables defers choice to the compiler and reduces your ability to force the compiler to find bugs at compile time.
The change is subtle. Although the body of the GetQuantity method has not changed; its ouput changes depending on the return type of GetQuantity.

Although still strongly typed, use of implicitly typed local variables defers choice to the compiler and reduces your ability to force the compiler to find bugs at compile time.

Recommendations:
  • Avoid using var with intrinsic types.
  • Use var with LINQ statements where the result is not an intrinsic type.
  • Prefer explicitly-typed local variables.


Comment and Contribute

 

 

 

 

 


(Maximum characters: 1200). You have 1200 characters left.

 

 

Sitemap