I’m Loving the .NET Fx ARM
Saturday, April 10, 2004
I enjoyed the annotations in The .NET Framework Standard Library Annotated Reference so much that I read them all in one sitting (in the bathtub, if you must know…). The annotations are where the authors put in their 2 cents about a particular class, method or property and it was very interesting. Here’s what I learned just from that part of the book:
- You shouldn’t use ApplicationException for custom
exceptions. Derive from Exception instead.
- Because
ICloneable.Clone doesn’t define whether it returns a deep or a shallow copy,
it’s practically worthless.
- Prefer UTF-8 because it takes
up the same amount of space to represent ASCII characters as ASCII, but can
also represent all Unicode characters (I knew that UTF-8 took up the same
amount of space but hadn’t yet jumped to “prefer”).
- I was
reminded of the System.Convert class, which does all of the same conversions
that the various type-specific ToXxx and Parse methods do, but puts them all
in one place.
- There’s another use for the private
interface method implementation syntax in C#:
class Enum : IEnumerator { object IEnumerator.Current { get { return this.foo; } } ... }
This syntax hides an interface method from general use unless you cast to the interface base class:Enum enum = new Enum();
The thing I never thought of that this enables is that it lets you override based on return type, which isn’t normally allowed in C#:
object obj1 = enum.Current(); // compile-time error
object obj2 = (IEnumerator)enum.Current(); // this worksclass Enum : IEnumerator { object IEnumerator.Current { get { return this.foo; }
Foo Current { get { return this.foo; } } ... }This private method implementation syntax lets you return the generic type as part of the interface implementation so that you can plug into standard idioms, e.g. foreach, but a more specific type for users of the type directly, saving the cast:
Enum enum2 = new Enum();
This will be less interesting as generics take over, but still, it’s a useful trick.
Foo foo1 = (Foo)((IEnumerator)enum.Current());
Foo foo2 = enum.Current(); // no cast required
- DateTime is always assumed to represent
local time, so if you convert to Universal time twice, you’ll change the
value each time.
- Since it’s possible to cast any number to
an enum value, e.g. TrueFalseEnum tfe = (TrueFalseEnum)42, make sure to
always check that an enum is a legal value. Theoretically this is a pain,
but in practice, I tend to check enum values with switch statements, making
the default case the error case, so it’s good to know that my code does the
right thing.
- The Threading.Interlocked class.
-
Jim Miller has way more birthdays than we do. : )
-
Jeff Richter agrees with me that the ThreadStart delegate needs an object
parameter.
- I should be using CompareInfo instead of
ToLower for case-insensitive comparisons (although they don’t show how):
using System.Globalization; using System.Threading; ...
CompareInfo compare = Thread.CurrentThread.CurrentCulture.CompareInfo;
if( compare.Compare("foo", "FOO", CompareOptions.IgnoreCase) == 0 ) {
Console.WriteLine("the same"); }
If I can get that much out of just the annotations, imagine what I could learn if I read the whole thing. : )