Hidden features of C#
stackoverflow.com
stackoverflow.com
public static IEnumerable<CalculatedTax> CalculateTaxes<T>(this T t)
where T : IOrderItems, IAddress {}
This adds an extension method to any type that implements those interfaces. Using this technique I have been able to make my interfaces much smaller and have generic functions which apply to many different types.Here's what it would might look like in Haskell:
calculateTaxes :: (OrderItems a, Address a) => a -> [CalculatedTax]Here's a full example in some production code. I ended up doing it this way to simplify some crazy legacy code. There were a bunch of different classes that provide order items and extended prices in different ways. With this setup as long as those types implement the necessary interfaces, they get those extension methods for free.
orderItems.CalculateTaxes();
If orderItems implements IOrderItems.Just have to include a using statement for the namespace it's in, it's an extension method. Look them up if you're unsure.
I didn't know you could do that with them, it's pretty cool. Although it's kinda what abstract classes and inheritance is for, but you can only inherit from one in C#.
A better title to this article would have been "Less Understood Features of C#," as things like nullable types, boxing and unboxing using as/is, readonly variables, Nullable<T>, type inferrence and most of the rest of the articles content should not be hidden to anyone who intends to have more than passing knowledge of the language. Most of the things mentioned by the post benefit from having the additional explanation so they can be understood well though.
public void IEnumerable<T>
{
IEnumerator<T> GetEnumerator();
}
The T type is only used in outputs in all the members. Therefore it can be declared with the `out` directive (i.e. public void IEnumerable<out T>). Covariance & contravariance doesn't work with classes, only with interfaces & delegates. Consider this delegate: public delegate void Action<in T>(T obj);
This can be declared with covariance (the in directive) because it only uses T in it's inputs. So an Action<string> can be passed into a method that takes Action<object>.Also, note that this doesn't work with T Func<T>(T obj) because it takes T as input & returns it (output). However, it does work with TReturn Func<in T, out TReturn>(T obj) because neither T nor TReturn is taken as both input & output.
Does this make more sense? It's a hard concept to fully understand
I don't want to sound snobbish, but at least 90% of that list I consider as a basic C# knowledge. If you don't know how to make an enumerable with yield, or insert some debug code with DEBUG or guard resource with using(), what exactly you know?
http://csharpindepth.com/Articles/Chapter11/StreamingAndIter...
I had used it to make a state machine but didn't know its relation to IEnumerable. The article was enlightening to a C# latecomer like me.
Instead of writing this pattern all the time:
StreamWriter writer = null;
try {
writer = new StreamWriter(filename);
// etc.
} finally {
if (writer != null) {
writer.Close();
}
}
You can just write this: using (StreamWriter writer = new StreamWriter(filename)) {
// etc.
}
Which does exactly the same thing. try { dobadthing(); }
finally { cleanup(); }
calls dobadthing(), which throws an exception; then cleanup() is called in case some recovery can be done, then the exception is thrown as if there were no try block.The garbage collector makes sure objects are properly disposed of. The only real cost to letting the collector handle it is that the object ends up surviving for an extra GC cycle. It's sloppy practice, and it means memory consumption will be higher if your program rapidly generates a lot of short-lived IDisposables, but otherwise the difference will probably be trivial.
The `foreach` statement and the `using` statement just so happen to desugar to similar code when it comes to handling IDisposable. The C# compiler will guarantee that Dispose() is called on the iterator and that code in the `finally` block will execute... even if you exit the loop early due to an `exception` or a break/goto. Just like the `using` statement.
The benefit is that it's even more of a pit-of-success feature than the `using` statement because you can't possibly forget to call Dispose().
It's also only slightly more work for the library author and slightly less work for the client but the client is going to use the code many more times than the author will write it.
01 void ExecuteSql(string sql)
02 {
03 connection.Open();
04 try
05 {
06 // execute SQL
07 }
08 finally
09 {
10 connection.Close();
11 }
12 }
And the effect here is that you have a function which still throws if your SQL is bad, but doesn't have the side-effect of leaving you with an open connection dangling about. That feels like a safer function to call.try/finally isn't something I find myself using very often at all, I think because the IDisposable pattern is actually translated into it - the code above is (nearly?) equivalent to;
connection.Open();
using(connection)
{
// execute SQL
}
so I guess IDisposable is the preferred way in MS' codebase.(All code is typed late at night into a textbox and totally untested. ;) )
PS: @politician confirms that `using` is translated to try/finally (http://news.ycombinator.com/item?id=3440969) so that's why you don't see it much -- `using` is syntactic sugar for it.
Unnecessarily catching exceptions you don't intend to deal with is a habit that is much more dangerous to stack traces, because it's easy to miss the huge semantic distinction between
// leaves the Exception's stack trace intact.
catch (Exception ex) { throw; }
and // Replaces the Exception's stack trace
// with a trace to the current execution point.
catch (Exception ex) { throw ex; }Otherwise yeah, no real surprises. Except maybe the Generic aliases.
http://stackoverflow.com/questions/tagged/hidden-features?so...
"Effective C#", and "More Effective C#"