C# tips, tricks and things you should know
During my previous holidays (i have to admit 1.5 months surfing in portugal) I had some literature with me which also included the book Programming .net components released with O'Reilly. It talks about the aspects of components in general and provides good examples how to achieve those in .net. Although these pages are a very good read (rather for experienced devs) for ppl interested in component development, I found it more interesting because of its general C# content. There are concepts & approaches, small tips & tricks and intersting things about C# which can be used not only in component based architectures and are therefore good to know anyway.
As I always make notes while reading "geek" books I thought: "so why not summarize them all up in a nice list and blog'em". Here we go...
1. implicit vs explicit interface
implicit interface implementation allows to use the interface member through an object or through the interface whereas the explicit interface implementation allows only access through the interface.
-
//public interface IInterface {
-
void Foo();
-
}
-
//implicit implementation
-
public AClass : IInterface {
-
public void Foo() { }
-
}
-
//explicit implementation
-
public BClass : IInterface {
-
void IInterface.Foo() { }
-
}
-
//usage implicit
-
a.Foo();
-
b.Foo();
-
//usage explicit
-
c.Foo();
-
d.Foo() //Fails because of explicit implementation!!!
Visual studio just offers the choice of the implementation but most people don't know the difference. With explicit implementation the server (implementing the interface) can prevent clients from using it directly on object which implements it. It forces that the members of the interfaces are only accessible via the interface itself
2. implicit vs explicit cast
this is just to get used to the terminology because a lot of guys are using it but don't know the terminology ;)
-
//implicit cast
-
T x = new T
-
//explicit cast
-
T x = (T)y
-
//explicit cast (defensive)
-
T x = y as T
Here you see that implicit casting is assigning a class instance directly to a variable. Explicit means casting from one type to another.
3. Destructors
A destructor of a class is defined with ~ClassName. In comparison to Dispose() the C# destructor is always called. Dispose() needs to be called by the client whereas the destructor is called when the garbage collector comes around. Best way is to implement both and channel the implementation to the method which does the cleanup. e.g. cleanup. Example of implementation [COMP05, 98]:
-
public class MyBase : IDisposable {
-
private bool _disposed = false;
-
protected bool Disposed {
-
get {
-
lock(this) {
-
return _disposed;
-
}
-
}
-
}
-
public void Dispose() {
-
lock(this) {
-
if (!_disposed) {
-
CleanUp();
-
_disposed = true;
-
GC.SuppressFinalize(this);
-
}
-
}
-
}
-
//the method for the subclasses if they need to release resources
-
protected virtual void CleanUp() { }
-
~MyBase{
-
CleanUp();
-
}
-
}
Classes deriving from this baseclass can now implement their destruction by overriding the cleanup method and can now decide to do the clean up manually (calling Dispose) or leave it till the GC comes around. Important here is that if Dispose() was called we tell the garbage collector to exclude this instance from being garbaged later (with GC.SuppressFinalize()).
4. use "Using" defensive
-
using (obj as IDisposable) {
-
}
This approach will only call Dispose() if the object implements IDisposeable. Good if you dont really know if the object needs to release resources or not and if you want to be ready for future changes. e.g. the server decides to implement IDisposeable.
5. Delegate inference
-
//instead
-
//u can use
-
publisher.someDelegate += someMethod
This is much nicer to read but only supported with .net 2.0.
6. Custom event arguments
Custom event arguments (own class derrived from EventArgs) should have only readonly members. This prevents the client from changing the values. Readonly members can only be assigned in the constructor so the publisher of the event is able to set the values when creating the arguments.
7. Always fire events in a try catch block
You never know what the event handler method of the client does, so its good to put the firing into a try catch block. You could write your own EventsHelper class [COMP05, 144] for the purpose of firing event within your classes.
-
public static class EventsHelper {
-
public static void Fire(Delegate d, params object[] args) {
-
if (d == null) return;
-
Delegate[] dels = d.GetInvocationList();
-
foreach(Delegate sind in dels) {
-
try {
-
sink.DynamicInvoke(args);
-
} catch {}
-
}
-
}
-
}
8. use "property-like" approach for event accessors
As you do with common member variables (expressing them with properties) you also should do this with events. This alows you to control the adding and removing of event handlers for your event.
-
public class MyClass {
-
MyHandler _myEvent;
-
public event MyHandler MyEvent {
-
add {
-
_myEvent += value;
-
}
-
remove {
-
_myEvent -= value;
-
}
-
}
-
}
9. Static objects as keys
-
myCollection[name] = "a name"
-
//instead of (old school)
-
myCollection["name"] = "a name"
a static object is created to act as a key for e.g. collections (because every instance is unique - has its own identity!). The advantage in comparison to the "old school" version (key is a string) is that the key is already available in memory wheras the string needs to be created everytime. If you use this key in a lot of places it could save some time.
10. Combine enumeration values
-
public enum color {
-
red,
-
green,
-
all = red | green
-
}
This example illustrates that it is possible to have enumeration values which accept more than one existing values of the current enumeration.
11. Singelton Application
A singelton application is one which only allows running one instance per machine. e.g. Microsoft Outlook is a singelton application. Everytime the user starts the application it will check if an instance is already running. If its not running it will launch it otherwise it will focus to the current one. The source for an application which runs only once is available in another post "Singelton Application with C#"
12. Containment
If it is not possible to derive from a class we use a class to wrap around the class we would like to inherit from. This procedure is also known as "Containment" (I mention it here because the this term is more unknown - usually developers use wrapper)
13. Use Debug.Assert()
The use of Debug.Assert should be used as often as possible. During the development the developer should "assert" things which always should be true. This helps finding bugs easier and its easier for other developers to understand the code.
-
int a = 10
-
int b = 20
-
int c = 20 - 10
-
Debug.Assert(c> 0, "i need it bigger than 0. check might be done in the future")
-
Console.WriteLine(10 / c)
This short example demonstrates that obviously the developer expects the variable "c" to be greater than 0. Why? Because in the next line he/she uses it for a dvision which would break with c = 0. If this is the case you would get an information seen in line 4. This concept is nice because it makes comments "active".
14. user string instead of String
String is just an alias for string and therefore its nicer to use the original type straight away. The same with int and Int32, etc.
15. Rethrowing exceptions
-
try {
-
} catch(Exception e) {
-
//some logging,etc...
-
throw;
-
}
This piece of code rethrows the exception. The interesting thing here is that you dont need to specify the Exception explicitly. Just the keyword "throw" is enough to rethrow the exception.
15. Code exclusion with attributes and not with #if .. #endif
-
[Conditional("DEBUG")]
-
void Foo() {
-
}
The advantage here is that the code is not reachable anymore if the condition is not met. This means that it will result in compile errors if you reference this method. #if ... #endif does not enforce this constraint. Its also nicer than the hash signs ;) Please check the MSDN Reference for more details about the conditional attribute.
Thats was it :) Hope there was something interesting and maybe new for everyone. I dont want to promote the book here but I really recommend it because it contains good content about programming with c# (and especially for component development) and should be read by every C# developer who wants to develop for enterprise.
Maybe you have some interesting tips & tricks which might be useful for others. Please be so nice and comment them... I am interested.
Resources:
[COMP05] .net Components, Juval Löwy, O'Reilly 2005 United States


July 29th, 2008 at 8:33 am
Really worthful tip and tricks on C#. :)
September 25th, 2008 at 12:15 am
This is an impressive and very useful set of tips. Thanks for taking the time to post these.