Update: 2018-05-16
Well, I can't believe it's been 8 years since I released these extensions! Since CodePlex has been discontinued, I have moved the code to GitHub. In Addition, I'd like to note that I now have a new library for .NET Core called Extenso, which has most of the core extenstions found here as well as some new featurs, such as my generic repository interface and base class, as well as a GenericODataController. Check it out on GitHub with a demo project to showcase the GenericODataController. I will be writing a new article for the Extenso library when I find the time, but for now, this little update will have to suffice. Enjoy!
Introduction
The purpose of this article is to demonstrate the usefulness of extension methods in the .NET framework and particularly the MBG Extensions Library at Codeplex (http://extensionslib.codeplex.com/).
There are quite a few free extension libraries out there, so why another one? Well, for me most of what was in the others I did not find very applicable to my own projects and I wanted to create something that would be reuseable across all my apps and wouldn't leave many methods feeling out of place in the API of most of my apps.
Using the Code
Reference the MBG.Extensions DLL and then add some using
statements for the namespaces you'd like to import. I will not go through each of the many extensions; that is something I will leave up to the reader. It is my intention to simply demonstrate some of the most useful ones here.
In()
This method resides in MBG.Extensions.Core
and is overloaded. So, how can this method help? Well, first we should look at some common development annoyances and then demonstrate the method to see just how useful it really is.
Here is a common thing we find ourselves doing as developers:
if (myString == "val1" ||
myString == "val2" ||
myString == "val3" ||
myString == "val4" ||
myString == "val5")
{
}
Surely, I'm not the only one who feels this is really nasty and wished for a better way. Well, read on friend! With the In()
method, you simply do this:
if (myString.In("val1", "val2", "val3", "val4", "val5"))
{
}
Wow, isn't that so much cleaner?!?
Now suppose that in fact you have an enumerable, perhaps a List<string>
and you want to know if a value is in there. Here's how one would normally do it:
bool found = false;
foreach (string s in myList)
{
if (myString == s)
{
found = true;
break;
}
}
if (found)
{
}
Now check this out:
if (myString.In(myList))
{
}
I know what you're thinking; dude, that's so cool! Yes, it has been a great help to me and here's something for those who may not quite have realised it yet: This can be used for ANY object type; string
s, int
s, enum
s, your own objects...
Let's say you have an enum
like so:
public enum MyEnum
{
MyValue1,
MyValue2,
MyValue3,
MyValue4,
MyValue5
}
Now you can do this:
MyEnum myEnum = MyEnum.MyValue1;
if (myEnum.In(MyEnum.MyValue2, MyEnum.MyValue3, MyEnum.MyValue5))
{
}
Enjoy!
So, what's next in the bag of tricks? Well, I'm glad you asked! Ever get tired of writing methods to serialize and deserialize your objects to XML? Well, the more savvy would already have created their own generic methods for this, but with extension methods we can take this a little further. So, without further ado, let's introduce these methods now, shall we?
XmlSerialize() and XmlDeserialize()
The XmlSerialize
methods reside in ObjectExtensions
and the XmlDeserialize
methods are in StringExtensions
and FileInfoExtensions
.
So, say we have an object called Employees
. We can serialize to file like so:
employees.XmlSerialize("C:\\employees.xml");
and deserialize like so:
FileInfo file = new FileInfo("C:\\employees.xml");
Employees employees = file.XmlDeserialize<Employees>();
or we might not want to serialize to file, so we could always use the overloads. Let's try this:
string xml = employees.XmlSerialize();
Employees employees = xml.XmlDeserialize<Employees>();
And here's a tip: Because of these methods, you can very easily add Load
and Save
classes to your custom objects like so:
public class EmployeeDetails
{
public static EmployeeDetails Load(string fileName)
{
FileInfo fileInfo = new FileInfo(fileName);
return fileInfo.XmlDeserialize<EmployeeDetails>();
}
public void Save(string fileName)
{
this.XmlSerialize(fileName);
}
}
Yay!!! Show me more! Okay, calm down...
Repeat()
Ever find yourself doing something like this...?
string separatorLine = "------------------------------------------";
Well, now you can save some time! How? Like this:
string separatorLine = '-'.Repeat(30);
There's also another Repeat
method on the StringExtensions
class as well, but it is not used quite as often and the method is the same. I'll leave that to you go explore.
IsMultipleOf()
Instead of this:
int i = 234;
if (i % 10 == 0){ }
We can now do this:
if (i.IsMultipleOf(10)){}
So much cleaner, right? If you're a tidy freak like me, you'll like that one too.
DataColumnCollection.AddRange()
Hey, how many times do you guys find yourselves copying and pasting when creating columns for a DataTable
? You normally end up with something like this:
table.Columns.Add("col1");
table.Columns.Add("col2");
table.Columns.Add("col3");
or:
table.Columns.Add(new DataColumn("col1", typeof(string)));
table.Columns.Add(new DataColumn("col2", typeof(bool)));
table.Columns.Add(new DataColumn("col3", typeof(int)));
Well, new extensions let you do this instead:
table.Columns.AddRange("col1", "col2", "col3");
or:
table.Columns.AddRange(
new DataColumn("col1", typeof(string)),
new DataColumn("col2", typeof(bool)),
new DataColumn("col3", typeof(int)));
ToCsv()
The best way to explain this one is just to show you! Try this:
myDataTable.ToCsv("C:\\csvTest.csv");
Ta da! Now you have a CSV file saved to disk. That simple!
DeepClone()
As the name suggests, this method will create a deep clone of your object. However, your object must implement ISerializable
for this to even show up in intellisense. In the future, I will look at doing this by reflection instead. Perhaps it can be improved and expanded to all objects.
GetAvailableSqlServers()
This will return a list of all SQL Servers available on your network. Ever wished to use a ComboBox
on your connection forms where there is now a TextBox
? Well, now you can use a ComboBox
and basically populate it with the list
returned from this method, like so:
cmbServer.Items.AddRange
(System.Data.Sql.SqlDataSourceEnumerator.Instance.GetAvailableSqlServers());
Miscellaneous SQL Client Methods
How many times have you had to write code to get a list of databases or tables from a SQL database? I got pretty tired of that after about the 999th time! So what did I do? I wrote the following extensions methods. Note that they are all on the SqlConnection
object.
GET DATABASE NAMES:
using (SqlConnection connection = new SqlConnection(ConnectionString))
{
cmbDatabase.Items.AddRange(connection.GetDatabaseNames());
}
GET TABLE NAMES:
using (SqlConnection connection = new SqlConnection(ConnectionString))
{
lbTables.Items.AddRange(connection.GetTableNames());
}
OTHER
Note that GetTableNames()
is overloaded so that you can provide a database name. Here, we just use the database from the connection string.
GetForeignKeyData()
and GetColumnData()
will provide you with details about the foreign key relationships and table schema. See the screenshot below for an example using the Northwind database.
Compression & Encryption
You will find some interesting methods on the FileInfo
class. Not only is there the aforementioned XmlDeserialize<t></t>
and BinaryDeserialize
<t>, but here you can also find the following extensions:
DeflateCompress
DeflateDecompress
GZipCompress
GZipDecompress
TripleDESEncrypt
TripleDESDecrypt
The encryption methods may not be exactly the way you'd like them implemented, but they do the trick. and you are most welcome to modify the methods in any way you see fit. ;-)
Web Browser: GetScreenshot / SaveScreenshot
These extensions are for the WinForms WebBrowser
control. GetScreenshot
will return a Bitmap
object and SaveScreenshot
will save the generated Bitmap
directly to disk. Please note that currently this does not work for all sites; especially SharePoint sites. I am no web expert (desktop development is my game), but I am guessing it has something to do with different "frames" or something. I racked my brain for ages trying to figure this one out. if anyone manages a solution, I will be eternally grateful and give full credit to him/her for it.
Other
Amongst others, there are extensions like:
IEnumerable<Person> myList = GetMyListData();
DataTable table = myList.ToDataTable();
Uri url = new Uri("http://www.codeproject.com");
if (url.Ping() == IPStatus.Success)
{
}
IPAdress ip = IPAdress.Parse("127.0.0.1");
if (ip.Ping() == IPStatus.Success)
{
}
string mySentence = "lower case";
string myPascalSentence = mySentence.ToPascal();
string myNonPascalSentence = myPascalSentence.SpacePascal();
Conclusion
Yes, extension methods are really helpful but they can also be very annoying when some people just bolt new stuff on willy nilly. My approach is to find what can benefit across multiple projects and try stick with those. Any time you find yourself doing something repetitive, there's a chance to ask yourself, is there a more efficient and/or elegant way to do this? Can I use an extension method to save time? If yes, the next question is; can I use this across multiple projects or will it look really out of place on most other projects? If you think it is reuseable, do your bit and share. Save all of us some time! Have fun guys!
History
Version 1.1, Released Oct 16, 2010
Many new extensions in this release.
Core.ByteExtensions
Core.ObjectExtensions
BinarySerialize
(overloaded) DeepClone
Data.Sql.SqlDataSourceEnumeratorExtensions
Data.SqlClient.SqlConnectionExtensions
CreateColumn
CreateTable
GetDatabaseNames
GetForeignKeyData
GetTableNames
(overloaded) GetColumnData
IO.FileInfoExtensions
BinaryDeserialize
GetFileBytes
Xml.StringExtensions
See SqlDemo
project for a treat! Enjoy!
============================================================
Version 1.2, Released Oct 28, 2010
[MBG.Extensions]
Core.ByteExtensions
RSAEncrypt
RSADecrypt
TripleDESDecrypt
Core.EnumExtensions
Core.EnumerableExtensions
ContainsAny
(Moved From ObjectExtensions
to here, where it should have been) ToDataTable
Core.ObjectExtensions
InvokeMethod
InvokeExtensionMethod
ParseOrDefault
TryParseOrDefault
Core.StringExtensions
ToPascal
TripleDESEncrypt
Core.UriExtensions
IO.FileInfoExtensions
DeflateCompress
DeflateDecompress
GZipCompress
GzipDecompress
TripleDESEncrypt
TripleDESDecrypt
Net.IPAddressExtensions
Reflection.TypeExtensions
GetExtensionMethod
(overloaded) GetExtensionMethods
Xml.XmlAttributeExtensions
Exists
GetValueOrSpecified
[MBG.Extensions.WinForms]
HtmlDocumentExtensions
DoPostback
(overloaded) GetElementByTitle
WebBrowserExtensions
GetScreenshot
(overloaded)* SaveScreenshot
(overloaded)*
*Note: Screenshots are not working for every site. SharePoint sites for example are particularly troublesome. I think it may have something to do with different "frames" or something. If anyone can fix this, I would really appreciate it and give full credit to that person.
============================================================
Version 1.3, Released Dec 06, 2010
[MBG.Extensions]
Collections.CollectionExtensions
AddIfNew
RemoveRange
(Moved From ListExtensions
to here, where it should have been)
Collections.EnumerableExtensions
ToCommaSeparatedList
has been replaced by:Join()
and ToValueSeparatedList
Join
is for a single line of values. ToValueSeparatedList
is generally for collection and will separate each entity in the collection by a new line character
ToQueue
ToStack
Core.ByteExtensions
Core.DateTimeExtensions
Core.StringExtensions
AddDoubleQuotes
AddSingleQuotes
Append
is now overloaded Between
IsNullOrWhitespace
IsPlural
LeftOf
(overloaded) LeftOfLastIndexOf
Pluralize
Prepend
is now overloaded RightOf
(overloaded) RightOfLastIndexOf
Singularize
Data.DataColumnExtensions
Data.SqlClient.SqlConnectionExtensions
CreateColumn
(Fixed bug with Unique Identifier columns) CreateTable
(Made some small changes and added an overload) Insert
(overloaded) InsertCollection
(overloaded)
IO.FileInfoExtensions
GetBytes
(Renamed From GetFileBytes
and added overload) TripleDESEncrypt
& TripleDESDecrypt
now not only return the encrypted / decrypted data, but actually Encrypt
/ decrypt
the file as well, as one would expect
IO.StreamExtensions
DeflateCompress
DeflateDecompress
GZipCompress
GZipDecompress
Reflection.ObjectExtensions
GetPrivateFieldValue
GetPrivatePropertyValue
GetPropertyValue
(overloaded) HasProperty
InvokeMethod
(Moved from Core.ObjectExtensions
to here) InvokeExtensionMethod
(Moved from Core.ObjectExtensions
to here) SetPrivateFieldValue
SetPrivatePropertyValue
SetPropertyValue
(overloaded)
Reflection.StringExtensions
ParseOrDefault
(Moved from Core.ObjectExtensions
to here) TryParseOrDefault
(Moved from Core.ObjectExtensions
to here)
Reflection.TypeExtensions
GetDefaultValue
IsCollection
Security.PrincipalExtensions
ServiceProcess.ServiceControllerExtensions
Text.StringBuilderExtensions
Append()
overloads: "params string[]
", "params T[]
" and "IEnumerable<T>
"
[MBG.Extensions.WinForms]
RichTextBoxExtensions
Highlight
(overloaded) HighlightAll
(overloaded)
[MBG.Extensions.WPF]
DependencyObjectExtensions