Stack OverflowHidden .NET Base Class Library Classes?
[+242] [88] John Sheehan
[2008-09-23 18:23:11]
[ .net hidden-features ]

What are your favorite lesser-known .NET Base Class Library classes and methods?

(11) Great question! The framework is so expansive that a lot of times one doesn't think to look (or doesn't know where to look) to the framework to achieve common (and sometimes not so common) tasks. - Giovanni Galbo
(6) Super-useful question! I found some really cool stuffs here. - aku
I didn't have to mark it, community wiki are excluded. Unmarked - John Sheehan
(3) I think it would be a mistake to delete this question - even though closed, it's a useful resource to have these answers here. - Bevan
while(true)Navigate(); - Shimmy
[+158] [2008-09-23 19:02:49] Doron Yaacoby

Path [1] class. I can't count the times the lack of its usage came up in code-reviews. People tend to go for the string concatenations and sub-stringage instead of using Path.Combine [2] and Path.GetFileNameWithoutExtension [3], among others.


(1) While I heartily agree, the Path class isn't actually a base class, is it? - Tor Haugen
(1) @Tor - Path is in mscorlib.dll, so it is most definitely part of the BCL - Richard Szalay
(12) You need to be careful with Path.Combine, if the second parameter starts with a "/", it may not do what you expect. - Noon Silk
The Path.Combine link has broken, it should point to - Stefan Monov
Also, what's so great about Path.Combine? Concatenation works fine for me. - Stefan Monov
@Stefan Monov: I just fixed the link. - Albic
(6) Seriously, why is this so upvoted? I never thought of Path as hidden... I've used it so many times already! And it was always there in the IO namespace, the kind of thing you import everywhere. - Camilo Martin
(2) @CamiloMartin: I think the issue is we all see (and sometimes even we do it ourselves for "quick" tasks) string concatenation when Path.Combine would be better and often more powerful. - Mark Hurd
[+140] [2008-09-23 19:13:23] C. Lawrence Wenham

System.Security.SecureString - More people should be aware of this if their program accepts passwords or passphrases, or stores credit card numbers in memory. SecureString values are stored encrypted (obfuscated, rather), but most importantly, they are never swapped to disk and can be disposed of immediately when you're done with them.

They're tricky to use because you can only build them one character at a time (to encourage you to build them by capturing keystrokes as the user types their password), and require three lines of code to recover and then wipe their plain text, but when used properly they can make a program more secure by avoiding the virtual-memory vulnerability.

// Make a SecureString
SecureString sPassphrase = new SecureString();
Console.WriteLine("Please enter your passphrase");
ConsoleKeyInfo input = Console.ReadKey(true);
while (input.Key != ConsoleKey.Enter)
   input = Console.ReadKey(true);

// Recover plaintext from a SecureString
// Marshal is in the System.Runtime.InteropServices namespace
try {
   IntPtr ptrPassphrase = Marshal.SecureStringToBSTR(sPassphrase);
   string uPassphrase = Marshal.PtrToStringUni(ptrPassphrase);
   // ... use the string ...
catch {
   // error handling
finally {

Edit: At the end of the example the SecureString is converted into a regular managed string, which makes it vulnerable again (be sure to use the try-catch-finally pattern to Zero the string after you're done with it). SecureString's use is in reducing the surface-area of attack by limiting the number of copies the Garbage Collector will make of the value, and reducing the likelihood of being written to the swap file.

The .Net framework is gaining more support for SecureStrings that help eliminate the need to decrypt it. The PasswordBox control in WPF stores its value in a SecureString, System.Diagnostics.ProcessStartInfo's Password property takes a SecureString, and so does the constructor for X509Certificate2. Some third party components are beginning to take it as native currency, too.

That is a good one. I'll have to bring it up in the next dev meeting. - TonyOssa
(10) At the end, you have "uPassphrase", again unscrambled and unlocked in memory. What was the point again? - David Schmitt
(3) David, you're right. I edited the answer to embellish on the correct use. - C. Lawrence Wenham
Wow, this can come in really handy. Thank you! - PhantomTypist
(9) Wow, this seems pretty paranoid - gn22
(4) Even with the edited answer, uPassphrase stays in memory unencrypted until the GC runs and it's overwritten with another new object. Due to the nature of the GC and managed memory, the only way to keep the string safe is to never put it in a System.String object. - Daniel
(2) I agree with Daniel and David: at some point you will have to copy your secure string into plain string, so what's the point? - Alek Davis
(1) SecureString is an IDisposable and thus should be managebly disposed. - Shimmy
[+120] [2008-09-24 03:14:28] Robert Paulson


When you're debugging, if the class is attributed, visual studio will display the information on mouse-over. It even allows you to put in properties of private fields, etc.

[System.Diagnostics.DebuggerDisplay("MyClass: ID={ID} Name={Name} ChildName={_child.Name}")]

Ref: msdn [1]


(1) Cool. I'm shocked I didn't know or forgot about this useful attribute. Thanks! - aku
You can customize it even further using the other properties on the DebuggerDisplay attribute. [DebuggerDisplay("Name = {Name}", Name="Alias #{AliasId}", Type="Person")] - CS.
I love this attribute -
(2) Can't you just implement ToString() in your class? - Si.
(5) @Si, What if you use ToString() for something else? Besides - why clutter up your actual class-code with things that should only be available when debugging? An attribute is clear, the name says it all, it's decoupled from the class itself (sort of), and it looks cool. ;) - J. Steen
(3) I wish standard C++ had this. - Kugel
[+85] [2008-09-23 18:51:15] RoyOsherove

This saves a lot of typing on strings:



string.IsNullOrWhiteSpace()  // .NET 4 only

Also a hidden gem using events; when declaring an event, a nice way to make sure you never need to check if it's null, is by initializing it to an empty anonymous delegate at declaration time:

public event EventHandler MyASimpleEvent = delegate {};

Nice technique! Don't know why I never thought of this myself... +1! - alastairs
this may cause a problem with asynch event dispatch, which allows only one delegate - Steven A. Lowe
Steven: since every delegate is a multicast delegate, you just pile more delegates on the current event. should not be a problem. just another call target in the list. - RoyOsherove
(10) Instead of creating all those anonymous delegates, just use an extension method to fire events and you only have one single place that checks if an event is null... myEvent.Fire(this, EventArgs.Empty);… - Max Schmeling
public static class StringExt { public static bool IsNullOrEmpty( this String value ) { return String.IsNullOrEmpty(value); } public static bool IsEmpty( this String value ) { return value == String.Empty; } - Ruben Bartelink
Not sure if I like... off to look for an extension classes library... (a la Frans Bouma's post) - Ruben Bartelink
(6) Beware using IsNullOrEmpty in VS2005 -… - Richard Szalay
(4) @Richard: This was fixed during CTP... - Erik Forbes
You are making an assumption with your event, you are not "making sure". Delegates are immutable, so every Delegate.Remove returns a new instance. And here's the deal: Calling Delegate.Remove on a Delegate with just that one last target method will yield ... null. How to get that target? The anonymous method does not capture locals/fields and thus will be static. So, doing this somewhere in your class should give you an NRE: MyASimpleEvent -= delegate{}; This could be called from anywhere, only the EventHandler must be assigned in the same class. Don't like unproven assumptions. ;-) - Robert Giesecke
[+77] [2008-09-23 19:03:47] RoyOsherove

A cool way to log the name of the current method you're in:

string myMethodName = MethodBase.GetCurrentMethod().Name;


(21) Bear in mind of course that the method you're in might be inlined. If you want to use the above method, mark your function as follows: [MethodImpl(MethodImplOptions.NoInlining)] - stusmith
Am I sick because I see people who I admire in the community and enjoy the fact that my rep is higher than theirs? I think I need to see a shrink. - Will
Yeah that definitely makes you sick. You should see a doctor about that. - yfeldblum
does this work work where new StackTrace.GetFrame(1).getMethod fails because of optimizations? - Maslow
so far it does, any idea what the syntax or namespace is for [MethodImpl(MethodImplOptions.NoInlining)] is in I'm not finding it - Maslow
(4) The method will NOT be inlined by the JIT, because it would change the behavior of the program. - Filip Navara
[+76] [2008-10-03 23:18:54] user20804

Getting the list of countries. Useful for populating the drop down box.

foreach (CultureInfo ci in CultureInfo.GetCultures(CultureTypes.AllCultures & ~CultureTypes.NeutralCultures
       RegionInfo ri = new RegionInfo(ci.LCID);


Wow...this is built int! No more Googling for the list of countries! - Omar
Hm, your code throws for me. Despite the apparent intention to exclude neutral cultures, it nonetheless seems to get a neutral culture and then fails at the RegionInfo statement. - Timwi
(4) Interesting, but doesn't work. - Shawn Wildermuth
[+70] [2008-09-23 18:59:22] C. Lawrence Wenham

System.Diagnostics.ConditionalAttribute. It makes the compiler ignore methods or classes that should only be active in certain build profiles. EG:

 private void DumpProperties()
     foreach (PropertyInfo prop in this.GetType().GetProperties())
         Console.WriteLine(prop.GetValue(this, null));

(1) Just to clarify this: you can safely call (in the above example) DumpProperties() in both debug and release, but in release it just won't do anything. - stusmith
Nice. I'll remember that one. - Will
(1) Is this the same as putting #ifdef DEBUG/#endif around the method contents? - Mark Pattison
(9) Mark, as clarified by stusmith, no it is not the same. In release, it can still be called, it just won't do anything. The advantage here is that you don't need to wrap #ifdef DEBUG around the method AND the calling code, just decorate the method with the attribute. Very clean. - Matt Olenik
(6) Just as a warning: if you call Method(i++) and the method is marked [Conditional("DEBUG")], then the i++ will be evaluated only in DEBUG mode, i.e. the variable i will have a different value depending on whether you’re in debug or release mode... - Timwi
[+65] [2008-09-23 19:54:20] community_owned

Most definitely String.Join(char separator, string[] list) to create "a,b,c" from {"a","b","c"}. This alleviates keeping track of a boolean to check whether the first item is already used.

(1) I keep forgetting this exists. I see (and sometimes write) way too much code that does it the unnecessarily hard way. - Kyralessa
(2) Make it an extension method on IEnumerable<string> for bonus points - George Mauer
[+65] [2009-08-25 20:48:27] David Basarab

Use the System.Diagnostics.Stopwatch [1]

Don't do StartTime with DateTime, and then EndTime with DateTime.

See this answer [2].


(3) I learned this one here :) - 280Z28
Just the clearify the answer. A DateTime value while having a 'ok' precision only gets updated about 10 times a second. The stopwatch class uses the 'system clock' for milliseconds precision. So the stopwatch is much better for high precision time measurements. - CodingBarfield
(9) If you do need to use DateTime.Now in situations where performance is a concern then it's good to be aware of DateTime.UtcNow which is faster (it doesn't need to calculate local time) - STW
Awesome! I've been looking for something like this. - PhantomTypist
Cool. Never knew about this one. Used to calculate the time elapse manually. - NLV
[+63] [2008-09-26 23:38:02] Carra

Using System.Environment.NewLine instead of "\r\n".

You meant, System.Enviroment.NewLine? - Erick Sgarbi
Fixed it for him - John Sheehan
when does this really matter beside of Mono ? - dr. evil
(3) Highly underused. +1 - Pat
@fm: Network-transmitted data? And Mono is quite a big part now (IMHO) of .NET development. - Lucas Jones
(9) I was surprised to find that this didn't work inside of the .NET compact framework. - Slapout
@Slapout, indeed, I was also very surprised and have to use "\r\n" anyway now everywhere. - Stormenet
(4) Why would you use \r\n at all ever anyhow? Almost all applications are perfectly happy with just a \n, as far as I can tell... - Eamon Nerbonne
(1) I was wondering why there isn't any VbCrLf substitute in C#. Thank you very much. - iSid
(4) @Eamon Nerbonne: I take it you've never tried to open and re-save anything from Notepad where only \n was used. To paraphrase, I'd argue: Why would you use \n at all ever anyhow? Almost all applications are perfectly happy with just a \r\n, as far as I can tell... - Dinah
[+62] [2008-09-25 04:39:15] Luke Foust



These allow you to build a connection string in a programmatic way without have to remember the specific syntax.

Documentation: DbConnectionStringBuilder on MSDN [1]


And when combined with a PropertyGrid it makes for powerful, but easily-programmed, database-agnostic connection setup forms. ;-) - qes
[+53] [2008-09-24 14:17:30] community_owned

Represents a dynamic data collection that provides notifications when items get added, removed, or when the whole list is refreshed.

Oh, interesting. I can see uses for this. - Camilo Martin
[+49] [2008-09-23 22:53:15] Mike Post

TextRenderer.MeasureText() is great for figuring out how large to draw your text. So often I see:

// this == something derived from Control
Size size;
using(Graphics g = this.CreateGraphics())
  size = g.MeasureString(this.Text, this.Font).ToSize();

When really all you need is:

Size size = TextRenderer.MeasureText(this.Text, this.Font);

The former is how you did it in 1.0 and 1.1; the latter is how you do it in 2.0+. It's much cleaner, doesn't requiring creating an object which must be disposed, and doesn't leave you open to accidentally not disposing of a resource. Plus if you use TextRenderer.DrawText() your text will look better and localize better [1]. This stuff just plain rocks when you're doing custom controls.

Edit: On the I18N/G11N front, here's more info: the shaping engines for international text have been updated quite a bit in the Uniscribe subsystem [2] of the Windows operating system, but not in GDI+ subsystem. So sometimes things looked strange/wrong if your .NET app was using the Graphics based method (AKA, GDI+). However, using the TextRenderer approach (AKA, Uniscribe) eliminates these problems and allows you to render text correctly (perfectly?) in the new locales introduced with Windows XP SP2 [3] (such as Bengali and Croatian). (Caveat emptor: I have no idea how or even if either of these methods play with vendor specific extensions to specific code pages.)


(3) Oh, where were you six months ago? - Robert Rossney
wish I could +10 this! - torial
[+46] [2008-09-23 21:12:40] Max Schmeling

IEnumerable<T> isn't used nearly enough if you ask me.

I find IEnumerable<T> far more useful than arrays and lists. You can easily optimize for very large data sets without having to load everything into memory to work with it. - spoulson
(1) Great for searching through CSV files for one. - Max Schmeling
(6) it's used everywhere in LINQ - Mark Cidade
(7) I was gonna say: LINQ is a game-changer as far as IEnumerable<T> is concerned. - Robert Rossney
(1) Don't forget IList<T> and ICollection<T> - Joel Coehoorn
In Haskell-speak, that's the "IEnumerable a" monad. SelectMany is a gamechanger as well - it's what happens when you use multiple from-clauses in linq. - yfeldblum
(3) Actually, LINQ uses IQueryable<T> everywhere, which implements IEnumerable<T>. - Daniel T.
(6) @DanielT that's not exactly true. When doing simple LINQ2Objects all the methods you call are defined on IEnumerable<T>. I don't think IQueryable comes into play until you start using a LINQ provider - George Mauer
[+39] [2008-09-23 20:30:15] Seb Nilsson

System.Convert [1] is a lot nicer than people think.

It's a bit more forgiving on what you put in. Use Reflector [2] to see how it converts between different types.

Ints are defaulted to 0 from bad input, bools to false and so on.

It's made int.Parse, bool.Parse and all other .Parse almost obsolete for me. TryParse is still usefull for the most secure parsing.


Thanks! This just saved me a heap of work. - Bevan
(16) Uhm what? System.Convert doesn't do that! It throws a FormatException generally speaking. There is one "gotcha", it does convert the null string into 0 - which, frankly, is a bug (MSDN sample code actually try..catches for a never-thrown ArgumentNullException, illustrating that the doc-writers themselves forget this gotcha...) - Eamon Nerbonne
[+32] [2008-09-23 18:24:09] John Sheehan

I didn't know about System.Net.WebClient [1] until it was posted in an answer to a question of mine [2].

WebClient client = new WebClient ();
client.DownloadFile("", "target.html");
client.UploadFile("", "hello.txt");

(9) And we don't know about it either, since your answer doesn't say a single word about it. - Kyralessa
the linked question says enough - John Sheehan
(6) WebClient is unhandy because it doesn't deal well with mime-types and in particular content-encoding. Better use HttpWebRequest; that at least lets you get at those crucial parts of the response when needed (with webclient, you're stuck) - Eamon Nerbonne
@Eamon, you can easily inherit from WebClient and customize the request before is is sent, so you can add features such as cookies, MIME types, encoding etc. if you want to - Thomas Levesque
@Thomas, re-invent the wheel much? - Devtron
(1) @Devtron, what do you mean? The WebClient doesn't support these features natively, I'm only saying they can easily be added. I'm not reinventing anything... - Thomas Levesque
[+32] [2008-09-23 21:31:06] Chris Pietschmann


Provides utility methods for common virtual path operations.

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs)

    Dim sb As New StringBuilder()
    Dim pathstring As String = Context.Request.FilePath.ToString()
    sb.Append("Current file path = " & pathstring & "<br />")
    sb.Append("File name = " & VirtualPathUtility.GetFileName(pathstring).ToString() & "<br />")
    sb.Append("File extension = " & VirtualPathUtility.GetExtension(pathstring).ToString() & "<br />")
    sb.Append("Directory = " & VirtualPathUtility.GetDirectory(pathstring).ToString() & "<br />")

    Dim sb2 As New StringBuilder()
    Dim pathstring1 As String = Context.Request.CurrentExecutionFilePath.ToString()
    sb2.Append("Current Executing File Path = " & pathstring1.ToString() & "<br />")
    sb2.Append("Is Absolute = " & VirtualPathUtility.IsAbsolute(pathstring1).ToString() & "<br />")
    sb2.Append("Is AppRelative = " & VirtualPathUtility.IsAppRelative(pathstring1).ToString() & "<br />")
    sb2.Append("Make AppRelative = " & VirtualPathUtility.ToAppRelative(pathstring1).ToString() & "<br />")

End Sub

:o I have been looking for this for a loooong time! And all this time I've had to stick with Server.MapPath - Jonn
[+32] [2008-09-27 03:38:25] Erick Sgarbi

Not really hidden but:

  • System.Drawing.Printing.PrinterSettings.InstalledPrinters: Returns a collection with all printer names installed in the machine.

(1) Good find! I can definitely use this in one of our projects. - PhantomTypist
[+31] [2008-09-25 23:58:04] Neil Hewitt
.HashPasswordForStoringInConfigFile(string password, string format)

Does the simple and common task of getting the MD5 or SHA1 hash of a given string. Since almost every system I have ever written stored password hashes instead of encrypted data or the plaintext, this is a godsend to avoid mucking about with the Crypto stuff.

Nice one, I didn't know about that method ! Too bad its hidden in an ASP.NET specific namespace... - Thomas Levesque
You would be much better off using bcrypt or another algorithm that utilises salts and key stretching. - Alex Barrett
Well, it's a given that you'd always salt the value you're hashing if it's for a login... this is just a quick way to gain access to the hash providers in the BCL in a single call. Since the original post I've added an extension method on String to our main utils library that does the same thing. - Neil Hewitt
[+31] [2008-09-24 09:22:32] aku

TypeConverter [1] class

It saved me a lot of time. And it helped Stack Overflow users to solve their problems:


Super useful class in certain situations. Back in v1.1 days I built a custom XML serialization engine (very narrow purposed) and TypeConverter ended up driving the conversion implementation of all but a few select types. Found the class using Reflector even. - qes
[+28] [2008-09-23 18:25:05] leppie

Buffer.BlockCopy [1]

Also StringReader [2] and StringWriter [3].

Oops forgot about: Debugger.Break [4]


Conditional breakpoints inside large loops. Debugger.Break is great! - roosteronacid
VS supports conditional breakpoints when debugging. Just right click on the red point you get when placing a breakpoint and select "Condition" - Sergej Andrejev
+1 for Buffer.BlockCopy, twice as fast as Array.Copy -
[+26] [2009-03-05 17:02:41] Brann

You can play default windows sounds this way :


(15) Sounds like fun! :) - Sandor Davidhazi
(3) this rules and will get added to every application I write now :) - jim
(1) I found this useful for debugging timing/threading related code. - AndrewS
Hm, I think these only work if you actually set windows sounds... - Gleno
[+25] [2009-03-10 23:02:52] Kyralessa

Tired of typing the unwieldy

string.Equals(x, y, StringComparison.CurrentCultureIgnoreCase)


Instead, try one of the properties on the StringComparer class:

StringComparer Properties [1]

Instead of the above, you can type:

StringComparer.CurrentCultureIgnoreCase.Equals(x, y);

Even though it's only slightly shorter, it's nice because it keeps the focus on the two things you're comparing, without the distraction of the StringComparison.CurrentCultureIgnoreCase parameter. And you can break it up if you like:

var comparer = StringComparer.CurrentCultureIgnoreCase;
comparer.Equals(x, y);

You should usually use OrdinalIgnoreCase - SLaks
(2) It entirely depends on what you're comparing and the reason for doing so. - Kyralessa
(1) I just create an extension method: static bool EqualsIgnoreCase(this string me, string that) { return string.Equals(me, that, StringComparison.CurrentCultureIgnoreCase); } - Mr. S
[+24] [2008-09-25 05:19:43] Jivko Petiov

HashSet<T>. It is a new class in the .NET Framework 3.5 and is very similar to List<T> only better.

(13) That is a subjective statement. A HashSet cannot store two elements that are equivalent, and it does not guarantee an enumeration order. If you need either of those, or the ability to index into the collection, then you'd need to use a List of some sort. - Marcus Griep
(14) HashSet is cool, but I wouldn't consider it at all similar to List ;) - Juliet
(32) No. It is not a replacement for List, it is a different data structure. - Matt Olenik
(3) thumb down simply because the statement is incorrect. The term better is dependent on the context it is being used. - user88637
[+23] [2008-09-23 18:47:28] Mitchel Sellers

For some reason many people don't kow about System.Text.StringBuilder. I couldn't live without it!

(1) The craziest thing about people not using this is that .NET strings are immutable, so a lot of string combining operations results in a lot of wasted memory (until the next GC pass). StringBuilder is wonderful because it avoids the creation of so many temporary strings -- just use it for concatenating three or more and pull out a proper string from ToString() when you need it. - Chris Charabaruk
[+23] [2008-09-23 20:08:03] zvikara

The BitConverter.ToString [1] method is very useful when working with binary data. I use it for debugging, traces and within unit testing.

It will take a byte array and return a printable string representation - something like "04-08-01-23-45-67-89-AB-CD-EF".

I also use Regex.Split(string, string) [2] for splitting a delimited strings.

It is somewhat similar to String.Split() [3], but using Regex.Split() is much more intuitive: Regex.Split() result string array only contain the data you need, while String.Split() result also contains the delimiters.


(12) String,Split removes the delimiters - Rune Grimstad
+1 for mention of BitConverter -
[+23] [2009-08-26 05:38:53] PVitt

String.Empty seems to be a hidden feature for many developers. String.IsNullOrEmpty(string) too.

... except that string.Empty is obsolete, and you should use "" now (it’s more readable, too). - Timwi
(3) @Timwi Where have you read that String.Empty is obsolete? The MSDN does not say anything about that. It even does not say that one should use "" instead of String.Empty. And readability is a very personal factor. - PVitt
(1) Fair point. So let me change my comment. Now I would say: How is string.Empty a “hidden feature”? It’s completely useless, you can just write "" instead. Why don’t we also have a char.Space for ' ' and an int.Zero for 0? :-p - Timwi
(7) Because String.Empty is static. A comparison with "" always creates a new instance of string that is only used for the comparison. Thus leads to many useless objects spread out over the heap. On the other hand String.Empty as a static field is only instanciated once at a time und does not pollute the heap. - PVitt
string.IsNullOrEmpty is for those who still don't know about string.IsNullOrWhitespace unless empty string check needed. - Shimmy
(3) @PVitt Actually, literal strings such as "" are placed in the CLR's string intern pool, so a zillion empty string literals should all resolve to the same address. - David Grant
[+23] [2009-08-25 20:40:49] David Basarab

Use this instead of concatenating the 2 strings yourself.

(2) I used this everytime I am concatenating file paths since I found out about it - Dan Seaver
(2) Another BCL that I've found to be a life-saver (even if not hidden) is System.Uri. I never realized the power of it until debugging an issue related to percent-encoding and had to really get under the hood. - STW
(2) It's not a straight concatenation... see:… - Shog9
[+21] [2008-09-23 22:21:59] Gulzar Nazim

This is cool. VisualStyleInformation Class [1] provides a lot of information about the current visual style of the operating system.

System.Diagnostics.Debugger.Break() [2] is used by virtually everyone but is very convenient for debugging .NET services.

NetworkChange.NetworkAvailabilityChanged Event [3] makes it easy to monitor network availability.


[+20] [2008-09-24 00:07:02] jesal

Here's a little snippet to tell which class/method the call is coming from. Useful in some special situations:

StackFrame frame = new StackFrame(1);
frame.GetMethod().Name; //Gets the current method name

MethodBase method = frame.GetMethod();
method.DeclaringType.Name //Gets the current class name

StackFrame and co are great for crawling up your stack to get the name of your test method for automatic intelligently named output. - Rick Minerich
(3) Unfortunately because of the way optimizations work, this isn't reliable. - Maslow
[+20] [2009-08-26 05:51:51] 280Z28

If you have a very complicated object to debug and don't want to spend the time creating a Visualizer to get a specialized view, you can use the built-in HTML Visualizer by creating a ToHtmlString() method in your class. This is based on the fact that the .NET debugger very reliably allows you to add function calls in your watch windows.

Here's an example I recently did of presenting an interleaved time-lapse view of the data state throughout a group of tasks:

Compiler State View

Do you have a bigger image? - spoon16
Heh, I just forgot to link to it. Fixed now, thanks. :) - 280Z28
Wow! Thanks.................... - SDX2000
What type does this ToHtmlString return?? - Shimmy
@Shimmy: just returns a string :) - 280Z28
[+19] [2008-09-23 18:46:43] John Sheehan

System.Web.UI.WebControls.MailDefinition [1]

"The MailDefinition class can be used by controls to create a MailMessage object from a text file or a string that contains the body of the e-mail message. Use the MailDefinition class to simplify creating predefined e-mail messages to be sent by a control."


[+19] [2009-03-10 13:27:27] SDX2000

WeakReference [1]. Extract from here [2] ...

The garbage collector cannot collect an object in use by an application while the application's code can reach that object. The application is said to have a strong reference to the object.

A weak reference permits the garbage collector to collect the object while still allowing the application to access the object.

This can be used to implement weak events, see here [3]

Deep comparison of XmlTrees

XDocument.DeepEquals [4]

Compares the values of two nodes, including the values of all descendant nodes.


[+18] [2009-08-25 20:48:47] marcc

I don't think it's a hidden feature, but I don't see it used often:


Quite useful when you have a pile of accessor-type functions or something which you don't want to be stepping into while debugging.

(3) I agree if it is used for accessor-type, but I have seen it abused, which hide bugs. - David Basarab
(1) It's a great way to exclude methods from code-coverage results as well, but as David mentions it can be abused. Still, my jack-knife can be abused--but that doesn't make it a great tool! - STW
(1) [System.Diagnostics.DebuggerNonUserCode] is a better answer if you just want to step over some code. It can easily be disabled in the IDE via disabling Tools->Options->Debugging->Just my code -
[+18] [2008-09-24 11:30:51] GvS

I just found:


Used to encrypt data for the current user or the local machine.

(1) Careful using this on webfarms, as this uses DPAPI. In other words the private key is stored in the user profile and that profile must be loaded prior to use. Also, loading profiles probably have an impact on memory utilization. - makerofthings7
[+16] [2009-09-22 18:59:09]

I have to add Exception.GetBaseException() [1]. I can't know how many times I've this code instead:

while(e.InnerException != null)
    e = e.InnerException;
return e.Message;

instead of just:

return e.GetBaseException().Message;

(1) +1 for being something I didn't know but I would consider the need to use this a code smell. Why would you need this realistically? For logging? For the love of god, use a logging framework - they all handle this for you. - George Mauer
[+15] [2009-07-21 15:55:05] HuBeZa

Convert hexadecimal\octal\binary string to decimal:

Convert.ToInt32("2A", 16); // equals 42
Convert.ToInt32("52", 8); // equals 42
Convert.ToInt32("101010", 2); // equals 42

A great way to convert numbers to byte array:

byte[] bytes = BitConverter.GetBytes(32767);

Or better, use Jon Skeet's MiscUtil [1] for endian bit conversion.


(3) 42, the answer to life, the universe, and everything. - Neil N
(2) And the opposite : Convert.ToString(42, 16). Interestingly, it works only for bases 2, 8, 10 and 16... other bases throw an exception. This is kind of strange, since the same implementation could support all bases up to 36 (at least). - Thomas Levesque
[+15] [2008-10-06 19:40:17] Robert Rossney

I'd have to say System.ComponentModel.BackgroundWorker.

It's not exactly easy to use, because you still have to understand how asynchronous method calls work, and you have to know about avoiding cross-thread exceptions, using Invoke to update the UI, etc. But it's considerably easier to use than System.Threading.Thread, which is what a lot of developers gravitate towards when they need to implement a background process.

[+14] [2008-09-24 00:23:57] user17222

String.Format(). Allows you to get rid of the wonkiness of "This" + " is" + " my favorite " + " Application";

(5) If you're not using formatting, you should consider using String.Concat() - it's even faster! - Richard Szalay
Surprisingly, I just ran a benchmark and discovered there's almost no performance difference concatenating 8 strings of various sizes. Here are Stopwatch times; 10000 cycles for each method: (Ticks StringBuilder: 1382273472) (Ticks String.Concat: 1379808306) (Ticks String PlusOp: 1363064136) - Triynko
(1) how come there's no ticks for string.format in here? - Maslow
(15) The compiler will transform ("a" + 5) to String.Concat("a", 5). It will also transform ("a" + "b") to "ab". - SLaks
[+13] [2009-01-04 17:26:32] xrost

Very helpful class to measure performance System.Diagnostics.StopWatch [1]
See detailed posts here [2]


-1 Duplicate:… -
[+11] [2008-10-25 18:04:54] Mike Two

More of a runtime feature, but I recently learned that there are two garbage collectors. The workstation gc and the server gc. Workstation is the default, but server is much faster on multicore machines.

      <gcServer enabled="true"/>

Be careful. The server gc requires more memory. See documentation [1] for more information.


This is awesome news! Thx for that - Peter Gfader
That is awesome....never knew it existed. - David Andres
[+11] [2009-07-27 11:18:00] dariom

I use these built-in delegate types (and their "overloaded" cousins) all the time:

Along with Lambdas is C# 3.0 they're pretty useful and can help make things more readable. (You can of course still use them with C# 2.0 and anonymous delegates).


[+11] [2008-09-23 20:21:38] Panos

System.Diagnostics [1] namespace contains many "hidden" gems. I have used extensively the DebuggerStepThroughAttribute [2], I have subclassed many times the TraceListener [3] class and I want to see in more detail the PerformanceCounter [4].


[+11] [2010-11-24 22:08:39] Aseem Gautam

Create custom size thumbnails from any image using System.Drawing.Image.GetThumbnailImage [1]:

public Image GetThumbnailImage (int thumbWidth, int thumbHeight,           
                GetThumbnailImageAbort callback, IntPtr callbackData)

Eg usage:

public static Image GetThumbnailFromImage(System.IO.Stream file)
    return Image.FromStream(file).GetThumbnailImage(48, 48, null, new IntPtr());

Very cool! Also fyi from MSDN: GetThumbnailImage method works well when the requested thumbnail image has a size of about 120 x 120 pixels. If you request a large thumbnail image (for example, 300 x 300) from an Image that has an embedded thumbnail, there could be a noticeable loss of quality in the thumbnail image. It might be better to scale the main image (instead of scaling the embedded thumbnail) by calling the DrawImage method - makerofthings7
[+10] [2009-08-25 20:56:31] STW

Here's one, inspired by Marcc [1]'s related Diagnostics attribute [2]:

System.Diagnostics.DebuggerDisplay [3]

It allows you to define the format of the string displayed in the Immediate / Locals window of Visual Studio, providing a string like "Person: {name} Cars: {cars.Count}" will display in the windows like "Person: John Doe Cars: 2".


This is handy. Failing this, you can also create a ToString() override. - Cheeso
(2) This also allows you to stop non-Pure property getters (ones whose evaluation has side effects on program state) from altering program state due to implicit func eval. - 280Z28
[+9] [2008-11-03 15:31:24] jon without an h

System.Runtime.Remoting.Proxies.RealProxy [1].

This class is pretty esoteric and normally only used in weird remoting scenarios; however, I have used it for the ability to dynamically implement an interface. It is also used by some mocking frameworks for the same purpose. See also Extending RealProxy [2].


[+9] [2008-10-20 18:27:39] Pradeep


[+8] [2009-05-14 20:14:50] bbmud

System.Net.Mail.MailAddress - no more regexp for server-side email address validation ;)

(2) No TryParse method... so you have to catch the exception, which is not so good. I still prefer to use a regex... - Thomas Levesque
[+7] [2009-01-05 19:39:33] John Sheehan

MatchEvaluator Delegate [1]: Represents the method that is called each time a regular expression match is found during a Replace method operation.


[+7] [2008-09-23 20:47:44] Jobi Joy

System.Linq is saving me a lot of time on Visual Studio 2008.

(1) Hard to call this 'hidden'. - p.campbell
[+7] [2008-09-23 18:28:59] Jason Z

System.Text.UTF8Encoding [1] for converting streams.


[+7] [2008-09-23 22:25:54] sallen

If you are drawing custom Windows Forms controls, then the following classes are essential for your OnPaint() method (or Paint event):

using System.Windows.Forms;

These classes all provide methods that will do most of the drawing work for you and keep your controls looking professional and native.


[+7] [2009-08-26 07:25:56] Chris Chilvers

If you're trying to convert between big/little endian then there is IPAddress.HostToNetworkOrder [1] and IPAddress.NetworkToHostOrder [2]. Why these methods were not part of the BitConverter class and in the obvious place people will look we'll never know.


But if you are on a big endian machine, HostToNetworkOrder would be BE->BE, no? - maxwellb
[+7] [2009-08-25 21:04:55] Chris Chilvers

TypeDescriptor [1] when using Windows Forms [2] data binding. This is how BindingSource can pretend to be any other object type.


you might have just answered a problem I've been having for a while... gotta go tinker with that! - STW
Yeah, in playing with that I've managed to data bind nested properties using a custom type descriptor and custom property descriptors to flatten out the hierarchy. Also had an object that contains a collection of objects, then presents all the properties in those objects as a single object so you could do multi-row select in a grid to a single details view, and databind the details view normally. - Chris Chilvers
(1) it looks like the ITypedList interface is closely related; it's a little cludgy to implement but some examples out there show it doing some pretty slick stuff :) - STW
[+6] [2010-07-21 12:17:46] amarsuperstar
string.Join([separator], [array])

Couple this with LINQ and it rocks!

string.Join(",", customers.Select(c => c.Name).ToArray());

All your customer names in a CSV with one line of code :-)

To quote a certain internet reviewer, "I like it!" - Kawa
(1) In C# 4, string.join now accepts a IEnumerable<T>. - Pierre-Alain Vigeant
(2) Just hope none of your Name properties have commas. - Joel Coehoorn
string.Join(",", customers.Select(c => string.Format("'{0}'",c.Name)).ToArray()); - iwayneo
(1) @iwayneo: I hope none of your Name properties have apostrophes. - Mark Hurd
i don't even remember writing that :) - iwayneo
[+6] [2008-09-24 12:57:21] Dror Helper

Using StackFrame to get information about calling method and running class. You can travel the stack and get the methodName, calling calss etc. You can get the stackFrame using

StackFrame frame = new StackFrame(n);

Where n is the layer above the current call And then you can retrive information by using its properties. for example use the following the get the information of the calling method:

MethodBase methodBase = frame.GetMethod();

[+6] [2008-09-23 18:29:23] Wayne

BaseValidator [1] Makes writing Custom validated controls much easier.


[+6] [2008-09-23 19:06:10] Bart Read


I hate having to do interop, and particularly PInvoke, but there are all kinds of goodies in Marshal for turning function pointers into delegates, and vice versa, turning Win32 error codes into something a little more helpful (often only a little though), and so on.

[+6] [2009-06-02 16:35:06] Nathan Koop

I came across this today System.Data.SqlTypes.SqlDateTime [1]

it has


among other methods & properties.


(1) Be warned that SqlDateTime overloads the comparison operators! If you are using it to validate that a DateTime is within the valid range of SqlDateTime, you may find the comparison throwing an exception. Compare against, ie., SqlDateTime.MaxValue.Value instead (which is a regular DateTime). - bsiegel
[+6] [2009-03-27 14:00:28] Simon Svensson

FormatterServices.GetUninitializedObject [1]

Creates a new instance of a type without calling any constructor. This will work with private constructors, non-parameterless-constructors, any type of constructor (since they aint called).

I believe this is the only way to ensure that a static constructor on a type is executed if you only have a Type instance. (You can not invoke it with reflection, and the Activator may fail due to nonmatching constructors.)

A somewhat esoteric problem, and solution.


(1) Actually, there's RuntimeHelpers.RunClassConstructor. See… - Joe White
(1) This is great for writting your own generic non-binary deserializer. The problem I had before I read your answer is that I was not able to create instances of types that do not have a public parameterless constructor. Thanks! - AgeKay
[+5] [2009-08-25 20:57:59] Cheeso

My favorite hidden feature is the SDK. OK, not very hidden, for some people, but most people seem to be able to develop .NET applications only with a tool or IDE, like Visual Studio. The SDK is free, and for small applications it's way quicker for me to write them up in emacs and then just build them with the command line compilers, csc.exe or vbc.exe.

Plus all the SDK tools are handy, too. XML Schema Definition Tool [1] (xsd.exe), Strong Name Tool [2] (sn.exe), and many others.


[+5] [2009-03-05 17:20:20] Pat

In line with String.IsNullOrEmpty().....



string s = String.Empty;
string s = string.Empty;

instead of

string s = "";

(3) public static readonly String Empty = ""; :) - Chris S
[+5] [2008-10-21 15:16:23] John Sheehan

System.Configuration.Install.AssemblyInstaller [1] to install services programmatically [2]


[+5] [2008-09-23 18:28:40] Kent Boogaart

FormatterServices [1]


[+5] [2010-04-09 16:15:36] Gabe Moothart

Membership.GeneratePassword() ( msdn [1]) will generate a secure temporary password for you.


[+4] [2010-07-28 18:48:03] HashName

System.Xml.XmlConvert [1] contains lots of nice static methods to convert between XSD types and .Net types.


[+4] [2009-08-26 05:33:58] 280Z28

I found several cases where people were not aware of certain properties of the Environment class. In particular, I cleaned up several places in code and changed it to:


[+4] [2009-08-26 05:40:53] 280Z28

The Managed, Native, and COM Interop Team [1] at CodePlex have released a modified, open source TlbImp tool [2] that allows simple creation of customized wrappers for pesky COM libraries.


[+4] [2008-09-23 20:58:37] Matthias

System.Environment [1] is one of my favorites. Especially the WorkingSet [2] property (gets the amount of physical memory mapped to the process context).


[+4] [2008-09-24 09:53:02] Dror Helper

Gets the path (and name) of the current running application.

I have a few related commands at my Blog [1]


[+4] [2009-07-27 10:37:27] blowdart

System.Security.SecurityElement.Escape [1]

Escapes XML entities from a string so you can use it within an XML element. It's used by the framework in generation WS-Security XML, but saves four string replace statements in your own code.


[+3] [2009-07-23 20:38:09] Dan Diplo

Easy way of making an MD5 or SHA1 hash [1]:

string hash = System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile("string to hash", "MD5");

Quick way of generating a unique, temporary file on disk:

string tempFilePath = System.IO.Path.GetTempFileName();

The System.Web.VirtualPathUtility [2] class also has some interesting methods for manipulating file paths.

Parse an enum into a string array in one line (eg. get all known colours from KnowColor enumeration into an array):

string[] colours = System.Enum.GetNames(typeof(System.Drawing.KnownColor));

If you want to annoy your server admin when he's at the console, add this to your web app :D


[+3] [2008-09-24 09:11:35] icelava

I like to use System.Collections.CaseInsensitiveComparer [1] to compare strings.


[+3] [2009-08-26 06:15:15] STW

Despite being in the Microsoft.VisualBasic.dll assembly, this method can be called by C# just as easily and can quickly let you know if the object being tested can be evaluated as a number.

Related to it are the various TryParse() methods, which attempt to evaluate an object as a number but don't raise exceptions if the call fails... These can be found under a variety of different types such as System.Int32 and System.DateTime

(1) You brought me back to my old VB6 days - HuBeZa
yeah, the Microsoft.VisualBasic assembly can carry some old smells with it--but there's a few goodies that can make it worthwhile to keep in mind. - STW
[+3] [2009-09-22 22:13:45] George Mauer

The Action lambda is a delegate and hence gets the same delegate goodies that regular ones do - such as BeginInvoke():

new Action(() => MethodIWantToRunAsychronously())
  .BeginInvoke(new AsyncCallback(x => ThingToDoWhenMethodReturns()), null);

What it does: Spawns a new thread and runs MethodIWantToRunAsychronously() on it while your continuing to execute the current method on the current thread. When MethodIWantToRunAsychronously completes, ThingToDoWhenMethodReturns() is called (still) on the new thread.

Can you explain what the code does? - Peter Mortensen
(10) It leaks memory. You MUST call EndInvoke. If you just want fire-and-forget, call ThreadPool.QueueUserWorkItem(() => SomeMethod()); - SLaks
Interesting SLaks. Had no idea. - George Mauer
re: ThreadPool.QueueUserWorkItem - this is used extensively in Monotouch apps to free the main thread while heavy crunching goes on in the bg. very useful - iwayneo
[+2] [2010-07-21 12:05:48] Freshblood

ToString() method of Object base class is really nice thing. Override it then bring mouse over instance variable in debug time after instance variable created. Don't even need DebuggerDisplay

class Program

    string name;
    string surname;
    static void Main(string[] args)
        Program instance = new Program() { name = "James", surname = "hetfield" };
    public override string ToString()
        return string.Format("name is {0}, surname is {1}",name,surname);

Ah thanks for editing. I forgot that ToString belongs to Object. - Freshblood
[+2] [2011-08-02 23:10:06]

System.Runtime.InteropServices.RuntimeEnvironment [1]

Most notably the GetRuntimeDirectory() method; however, there are several useful methods there.

    // Show whether the EXE assembly was loaded from the GAC or from a private subdirectory.
    Console.WriteLine("Did the {0} assembly load from the GAC? {1}",
    // Show the path where the CLR was loaded from.
    Console.WriteLine("Runtime directory: {0}", 
    // Show the CLR's version number.
    Console.WriteLine("System version: {0}", 
    // Show the path of the machine's configuration file.
    Console.WriteLine("System configuration file: {0}", 

[+2] [2009-08-26 14:15:58] skevar7

[System.Diagnostics.ConditionalAttribute] - can be used instead of ugly preprocessor directives. For instance:

public void Validate()
    // ...

aesthetically it's better, but I'm not a big fan of having code being omitted from the compiled assembly. Just my $0.02 - STW
(1) Already an answer with higher votes. Please delete. - Pat
[+2] [2009-03-27 13:46:31] Chris S

This isn't really a method but just something I found in the String [1] class source:

// The Empty constant holds the empty string value.
// We need to call the String constructor so that the compiler doesn't mark this as a literal.
// Marking this as a literal would mean that it doesn't show up as a field which we can access 
// from native.
public static readonly String Empty = "";

[+2] [2009-05-07 10:57:24] Think Before Coding

Decimal preserves trailing zeros :

decimal x = 1.0m;
decimal y = 1.00m;
decimal z = 1m;

Assert.IsTrue(x == y);
Assert.IsFalse(x.ToString() == y.ToString());

Assert.AreEqual("1.0", x.ToString(CultureInfo.InvariantCulture));
Assert.AreEqual("1.00", y.ToString(CultureInfo.InvariantCulture));
Assert.AreEqual("1", z.ToString(CultureInfo.InvariantCulture));

Assert.AreEqual("1.000", (x*y).ToString(CultureInfo.InvariantCulture));

This behavior is documented in the MSDN library.

The decimal.Parse method keeps track of trailing zeros too :

decimal x= decimal.Parse("1.0", CultureInfo.InvariantCulture);
decimal y= decimal.Parse("1.00", CultureInfo.InvariantCulture);

Assert.AreEqual("1.0", x.ToString(CultureInfo.InvariantCulture));
Assert.AreEqual("1.00", y.ToString(CultureInfo.InvariantCulture));

[+2] [2008-09-27 03:13:06] torial

The DebuggerStepThroughAttribute is great for properties and also for those helper functions that you have no desire to step through. Unfortunately, it seems rarely known:

[+1] [2008-10-06 18:59:09] John Chuckran

Expanding the My Namespace has always been useful to me

Namespace My

    <Global.Microsoft.VisualBasic.HideModuleName()> _
    Friend Module MyStuff
        Sub Foo()

        End Sub
    End Module

End Namespace

(2) In what way has it been useful to you? - Peter Mortensen
[+1] [2009-04-07 07:01:57] Peter Gfader

Ignore Attribute [1] on Unit-Tests for ignoring slow performance tests during development


[+1] [2008-09-24 09:48:35] Dror Helper
public static int Compare(string strA, string strB, bool ignoreCase)

Great to compare two strings with possible difference in letter case.

[+1] [2008-09-23 22:56:45] Slace

For generating code files I like System.CodeDom.

[+1] [2009-08-26 05:47:07] 280Z28

If you have a custom MSBuild task in your project that processes a file and subsequently creates .cs files to include in the same build, changes to the source file of the transformation often won't show in debugging without building twice. When you are generating a single file based solely on the content of a single source file, this task is best solved with a SingleFileGenerator. For multiple inputs and/or outputs, you may be stuck with an MSBuild task. In this case you can fix Visual Studio's dependency analysis by adding the following to your .csproj file:


It's introduces a few other annoyances, but it will allow you to have deterministic, correct single builds (a rather important goal).

[+1] [2011-08-11 15:59:10] Thomas Levesque

I recently discovered the ProtectedData [1] and ProtectedMemory [2] classes, which allow you to use the Data Protection API from .NET. It's a nice way to encrypt user credentials for storage in applications that need to authenticate on a remote server.

public static string EncryptPassword(string password, byte[] optionalEntropy = null)
    byte[] clearTextBytes = Encoding.UTF8.GetBytes(password);
    byte[] encryptedBytes = ProtectedData.Protect(clearTextBytes, optionalEntropy, DataProtectionScope.CurrentUser);
    return Convert.ToBase64String(encryptedBytes);

public static string DecryptPassword(string encryptedPassword, byte[] optionalEntropy = null)
    byte[] encryptedBytes= Convert.FromBase64String(encryptedPassword);
    byte[] clearTextBytes = ProtectedData.Unprotect(encryptedBytes, optionalEntropy, DataProtectionScope.CurrentUser);
    return Encoding.UTF8.GetString(clearTextBytes);

[+1] [2010-02-24 05:58:46] ligaoren

FormatterServices.GetUninitializedObject Activator.CreateInstance

Has someone mentioned above two?

Yes, they have. Please delete. - Pat