Extension methods in C#

Introduction

Extension methods in C# allow you to extend the functionality of types that you didn’t write and don’t have direct access to. They look like integral parts of any built-in classes in .NET, e.g.:

DateTime.Now.ToMyCustomDate();
string.ToThreeLetterAbbreviation();

You can extend the following types in C#:

  • Classes
  • Structs
  • Interfaces

You can extend public types of 3rd party libraries. You can also extend generic types, such as List of T and IEnumerable of T. You cannot extend sealed classes.

Extension methods are often used to extend the functionality of the code which is out of the developer’s control, like a 3rd party code base. They also come in handy when extending a class without inheritance or composition.

The basics: extending system types

Open Visual Studio and insert a new blank solution called ExtensionMethods. Add to this a C# class library called ExtensionMethods.ExtensionSamples. Insert a folder called Basics to the library project. Insert a class called SampleExtensions to this folder. There are a couple of rules around constructing extension methods:

  • The containing class, like SampleExtensions in this case, must be public and static
  • The extension method itself must be static
  • The type you’re extending must be provided as the first argument in the parameter list. It also must be provided with the ‘this’ keyword

So if you want to extend the System.DateTime class with a method that returns a string then you’ll need the following structure:

public static class SampleExtensions
{
	public static string ToCustomFormat(this DateTime dateTime)
	{

	}
}

This will ensure that whenever we use a DateTime object we can call the ToCustomFormat() method on it. Let’s just add some dummy return value to the method:

public static string ToCustomFormat(this DateTime dateTime)
{
	return "This is some custom datetime format.";
}

Let’s see how you can call this method. Add a new Console project called ExtensionCaller to the solution and add a reference to the library project. Add the following code to Main:

string customDateFormat = DateTime.Now.ToCustomFormat();
Console.WriteLine(customDateFormat);
Console.ReadKey();

You’ll notice that the compiler doesn’t like it:

‘System.DateTime’ does not contain a definition for ‘ToCustomFormat’ and no extension method ‘ToCustomFormat’ accepting a first argument of type ‘System.DateTime’ could be found

You need to add a using statement to the namespace where the extension method is located in Program.cs:

using ExtensionMethods.Extensions.Basics;

The code should compile now. Run the code and you’ll see our little string “This is some custom datetime format.” printed on the console windows. Congratulations, you have just added custom functionality to a native .NET type that is clearly out of direct control.

You can also provide “normal” input parameters to extension methods. All parameters after the first ‘this’ will be input parameters. Let’s see how we can extend the built-in String object. Back in SampleExtensions.cs add the following method:

public static string ToEmail(this string fullName, string nickName, int yearOfBirth)
{
	return string.Concat(fullName.ToLower().Replace(" ", "."), yearOfBirth, "@", nickName.ToLower().Replace(" ", string.Empty), ".com");
}

You can use it from Main as follows:

string fullName = "Elvis Presley";
int birthYear = 1935;
string nickName = "King of Rock and Roll";
string email = fullName.ToEmail(nickName, birthYear);
Console.WriteLine(email);

The output should be elvis.presley1935@kingofrockandroll.com. As you start typing “fullName.” IntelliSense will find the extension method and denote it with a little downward pointing arrow. That’s a telling sign of extension methods: you’ll know you’re not using a native, built-in method of the type if you see that arrow. You’ll in addition see “(extension)” in the description provided by IntelliSense. If IntelliSense doesn’t find the method you’re looking for then double check if the correct namespace has been referenced among the using statements. It won’t find the correct namespace for you. In all other aspects extension methods behave just like normal methods do.

As you see extension methods can be located in just any assembly within your solution. They can also reside in any namespace, even namespaces you don’t own, such as System.String which will alleviate the problem mentioned in the previous paragraph, i.e. the need to import the namespace where the extension method is located. Just make sure to reference the correct library and namespace in the consuming classes. Also, the static class encapsulating the extension methods can have any name as it won’t appear in the consuming classes: normally the word “Extensions” is added to the class name for clarity, such as “StringExtensions”, “DateExtensions”, “PriceExtensions”, but it could be MickeyMouse or DonaldDuck as well.

Let’s continue with more examples. Add a new folder called Strings to the ExtensionSamples project. Add a new class called CustomStringExtensions and make it public and static. Change the namespace to simply “System”. Add the following extension method:

public static string ToXmlName(this string name)
{
	return string.Concat("<name>", name, "</name>");
}

In Main start typing the following:

string xmlName = fullName.tox

IntelliSense will find the ToXmlName() method for you because there’s no extra namespace that must be imported. System is already present:

string xmlName = fullName.ToXmlName();

Let’s see how to add an overloaded extension method:

public static string ToXmlName(this string name, string customAttrib)
{
	return string.Concat("<name attrib=", customAttrib, ">", name, "</name>");
}

So in fact it’s not much different from overloading “normal” methods except for the ‘this’ parameter.

In Main:

string xmlName2 = fullName.ToXmlName("singer");

IntelliSense will show both methods but hides the ‘this’ parameter. It will only show the possible input parameters.

Extending interfaces

Add a new folder to the ExtensionSamples project called Interfaces. In this folder add a new class called Product:

public class Product
{
	public int Id { get; set; }
	public string Name { get; set; }
}

Imagine that the products can be retrieved from a variety of repositories which all implement the following interface:

public interface IProductDataSource
{
	IEnumerable<Product> GetProducts();
}

Also, they inherit from separate abstract classes. This shows the scenario that each repository is different enough so that it’s not reasonable to make them inherit from the same abstract base class:

public abstract class FileSourceBase
{
	public string FileName
	{
		get
		{
			return "source.xml";
		}
	}
}

public abstract class DatabaseSourceBase
{
	public long Size
	{
		get
		{
			return 1000;
		}
	}
}

public abstract class ApiSourceBase
{
	public string Username
	{
		get
		{
			return "apiuser";
		}
	}
}

Add the following implementations:

public class ApiSourcepublic : ApiSourceBase, IProductDataSource
{
	public IEnumerable<Product> GetProducts()
	{
		return new List<Product>() { new Product() { Id = 5, Name = "Fifth" }, new Product() { Id = 6, Name = "Sixth" } };
	}
}

public class FileSource : FileSourceBase, IProductDataSource
{
	public IEnumerable<Product> GetProducts()
	{
		return new List<Product>() { new Product() { Id = 3, Name = "Third" }, new Product() { Id = 4, Name = "Fourth" } };
	}
}

public class DatabaseSource : DatabaseSourceBase, IProductDataSource
{
	public IEnumerable<Product> GetProducts()
	{
		return new List<Product>() { new Product() { Id = 1, Name = "First" }, new Product() { Id = 2, Name = "Second" } };
	}
}

A common functionality needed from each data source is to search for specific products regardless of the source, e.g. retrieve all products whose name includes “f”. The goal is now to add this function by an extension method. Add a new class to the same folder called DataSourceExtensions and make it… …public and static, as you know by now. Double-check that the namespace is the same as for the IProductDataSource interface. This is so that the extension will be available anywhere the interface is available without the need to add extra using statements.

Add the following stub extension method which extends the interface:

public static IEnumerable<Product> SearchProduct(this IProductDataSource source, string searchTerm)
{
	return null;
}

It can be called from Main as follows:

IProductDataSource productDataSource = new DatabaseSource();
IEnumerable<Product> products = productDataSource.SearchProduct("f");

We had to import the namespace of the interface but then the SearchProduct extension was readily available. The implementation of the method is simple as each concrete class has a method which returns all products. All we need is some LINQ search:

public static IEnumerable<Product> SearchProduct(this IProductDataSource source, string searchTerm)
{
	return from p in source.GetProducts() where p.Name.ToLower().IndexOf(searchTerm.ToLower()) > -1 select p;
}

As we’re extending an interface, the extension method will be available for all implementing types. There’s no need to cast the concrete type to an interface type. Also, if you get new implementing classes in the future then the extension method will be automatically available for them as well.

Arrays and collections

Open up the demo project we’ve been working on in this series. Locate the ExtensionSamples project and add a new folder called Collections. We’ll reuse much of the code we added to the Interfaces folder. Here we want to introduce another search functionality similar to the SearchProduct extension which searched through one specific data source. We now want to search through all data sources in one call. Add a class called ProductCollectionExtensions to the Collections folder and make it public and static. Make sure that the namespace is the same as for the IProductDataSource interface to avoid having to copy namespaces. Add the following extension method stub:

public static IEnumerable<Product> GetAllItemsByName(this IProductDataSource[] productDataDources, string searchTerm)
{
	return null;
}

You can see that we’re extending an array of product data sources. We want to search through all data sources and find a product with some name in all those sources.

A method call from Main looks like this:

private static void TestCollectionExtensions()
{
	IProductDataSource[] dataSources = new IProductDataSource[] { new DatabaseSource(), new FileSource(), new ApiSource() };
	string searchTerm = "f";

	IEnumerable<Product> productsWithId = dataSources.GetAllItemsByName(searchTerm);
}

In the method implementation we can reuse the already existing SearchProduct extension on each data source in an iteration:

public static IEnumerable<Product> GetAllItemsByName(this IProductDataSource[] productDataDources, string searchTerm)
{
	List<Product> products = new List<Product>();
	foreach (IProductDataSource productDataSource in productDataDources)
	{
		products.AddRange(productDataSource.SearchProduct(searchTerm));
	}
	return products;
}

Yet again we extended the functionality of IProductDataSource without having to touch the code in the concrete classes.

This was an example of how to write extensions for arrays. The same applies for all types of sequences, such as IEnumerable, List, IList etc. The GetAllItemsByName method can equally be written as follows:

public static IEnumerable<Product> GetAllItemsByName(this IEnumerable<IProductDataSource> productDataDources, string searchTerm)

The code will still compile as an array is also an IEnumerable so the change in the signature doesn’t break the existing code. You can call the GetAllItemsByName on any collection that implements the IEnumerable interface such as a List of T or HashSet of T.

Extending any object

What if you want to make an extension method available on just any type of object? It’s certainly possible. There’s nothing stopping you from declaring the ‘this’ parameter on the built-in type Object. There are scenarios where this is feasible, such as cross-cutting concerns: logging, caching and the like.

Add a new folder in the ExtensionExamples project called Objects. Add a new class to it called ObjectExtensions and declare it public and static. Make sure that the namespace is System. This will ensure that the extension will be available everywhere throughout the solution as System is referenced by default. In general you can restrict the IntelliSense visibility of an extension method by controlling its namespace.

Let’s say we want to be able to get the XML representation of any object for logging purposes. Add the following – admittedly very primitive – implementation to the object extensions class:

public static string ToXmlRepresentation(this object target)
{
	return string.Concat("<xml>", target.ToString(), "</xml>");
}

An exact implementation is beside the point here. The extension method can be called from Main like this:

private static void TestObjectExtensions()
{
	Product p = new Product() { Id = 1, Name = "product" };
	int i = 5;
	string s = "hello";
        DateTime now = DateTime.UtcNow;
	string xmlProduct = p.ToXmlRepresentation();			
	string integerXml = i.ToXmlRepresentation();
	string stringXml = s.ToXmlRepresentation();
        string dateXml = now.ToXmlRepresentation();
}

The extension method will be available on all elements that derive from the Object class: integer, string, built-in objects, interfaces, your custom objects etc.

Types

We can extend Types as well. Add a new class called TypeExtensions to the Objects folder. Make it public and static and change the namespace to System. Let’s say we need some metadata of any Type in .NET:

public static string GetTypeMetadata(this Type target)
{
	return string.Concat("Assembly: ", target.AssemblyQualifiedName, ", name: ", target.FullName);
}

From Main:

private static void TestTypeExtensions()
{
	Product p = new Product() { Id = 1, Name = "product" };
	int i = 5;
	string s = "hello";
	DateTime now = DateTime.UtcNow;
	string productMetadata = p.GetType().GetTypeMetadata();
	string integerMetadata = i.GetType().GetTypeMetadata();
	string stringMetadata = s.GetType().GetTypeMetadata();
	string dateMetadata = now.GetType().GetTypeMetadata();
}

Limitations

You can achieve a lot with extension methods but not everything. In particular you cannot extend the state or accessibility of an object. As extension methods are defined in a separate public static class only those properties and methods will be available to the extension method that are accessible to the class holding the extension methods. You cannot of course reference private properties of an object you’re trying to extend. This is the normal and expected behaviour, extension methods are no exception to the accessibility rules.

You cannot create new instances of an extension method class as it is static. You cannot add instance level fields or properties to it for the same reason. You can certainly add private static fields to an extension method class and maintain some state in them for the incoming object instance. However, as it is a static field it won’t ever be collected by the garbage collector. It will just keep growing.

If you absolutely need to access a private field of the object you’re extending then Reflection can come to the rescue. Imagine that our Product class has a private field with a default value:

private string _privateField = "default";

We can have an extension method like this:

public static string DoSomethingWithPrivateField(this Product p)
{
	FieldInfo fieldInfo = typeof(Product).GetField("_privateField", BindingFlags.Instance | BindingFlags.NonPublic);
	string privateFieldValue = (string)fieldInfo.GetValue(p);
	return privateFieldValue;
}

This means that Reflection will look for a private instance variable called “_privateField” on a Product object. Then we call GetValue and specify that it should be the incoming “p” where the private field should be found.

Call it from Main:

private static void TestPrivateField()
{
	Product p = new Product();
	string privateField = p.DoSomethingWithPrivateField();
}

There you have it, the extension method will find the value of the private field. However, keep in mind that reflection is “expensive” so don’t overuse it. Also, there’s no guarantee that the name of the private field won’t change in the future and the code may break at any point in the future.

Therefore it’s not recommended to use private static variables to keep track of the state or reflection to read private variables from an object. Use them only if there’s no other solution and use them with special care.

Extension methods can obviously only extend objects that are visible to the containing class, such as other public classes. You cannot extend private classes of course or any other class that’s not visible from another class. This is not surprising: extension methods are very much like normal methods and the same basic accessibility rules apply to them as to any other class.

If you create an extension method with the same name as a method that already exists in the class then the compiler will call the class definition. In other words extension methods have a lower priority than class methods and there’s no way around that rule. All you can do is rename the extension method. This can be confusing at first because you won’t get any compiler error or runtime exception but your extension method will not be called.

If you have two extension methods with the same name that extend related types of objects, such as IEnumerable of String and List of String then the extension method with the most specific match will be called. In that case if I call (List of String).ConvertToSomethingElse() then the List of String extension will be called and not IEnumerable of String if you have the following methods:

ConvertToSomethingElse(this List<String> list);
ConvertToSomethingElse(this IEnumerable<String> list);

The same is true if some object implements an interface:

ConvertToSomethingElse(this int integer);
ConvertToSomethingElse(this IConvertible list);

Integer implements the IConvertible interface. So if we call (some integer).ConvertToSomethingElse then both extension methods could apply. The compiler will select the one that extends the Integer type as it is the closest match. If you cast the integer to IConvertible…:

((IConvertible)input).ConvertToSomethingElse();

…then the IConvertible version will be called.

One more limitation, which is not really a limitation but normal behaviour, is that if you define two extension methods with the same signature in the same namespace but different files then the compiler will complain. It’s because it cannot select the correct one. You get the same compiler error if you define two “normal” methods with the same signature in the same class: the compiler will complain about ambiguous references. Keep this in mind when changing the namespace to something too wide, like “System” as some other programmer working on the same project may do the same and there’s a risk of declaring the same signatures leading to a compiler error.

Keep in mind that extension methods are really just syntactic sugar added to .NET. They add functionality to the objects they extend without changing the object definition in any way. This explains why we have the above limitations.

Portability

Extension methods are portable to a high degree with some tricks:

  • Visual Basic projects can call extension methods written in C# as long as there’s no .NET profile mismatch
  • Using an extension method written in .NET4.5 C# library cannot be used directly in a project with no full .NET, e.g. a Windows Phone project with a specific runtime. You can only reference an extension method contained in a Portable Class Library project from a Windows 8/Phone app. When you create a Portable Class Library you can select which frameworks to support: WP8, Windows Store apps, Silverlight 5 and .NET4 and above. Creating an extension method in a portable class library follows exactly the same process as we’ve seen so far. Portable libraries can be referenced from non-portable libraries as well.
  • Extension methods written in .NET4.5 cannot be used in assemblies that target a lower .NET version or a limited profile, like the Client profile. In this case not even a portable client library can be used. In that case what you can do is create a separate C# library, retarget it to a lower .NET framework or profile, such as .NET3.5 Client Profile, and add the extension method in the original C# library as a link: Add Existing Item…, navigate to the cs file containing the extension methods. Before clicking Add in the Add Existing Item window click the little downward pointing triangle on the right side of the Add button. You’ll see two options there: Add and Add Link. Select Add Link. This will at least ensure that the same source code is shared between the original C# library and the one targeting a lower .NET version. Keep in mind that .NET3.5 is the earliest framework where you can use extension methods.

Exceptions

Extending exceptions can be useful if you’d like to get a user-friendly output of wrapped exceptions. You normally don’t want to show the full stacktrace of the top-level and wrapped exceptions to a user. The following extension method collects the exception message from the inner exceptions as long as they are not null:

public static string UserFriendlyFullMessage(this Exception exception)
{
	StringBuilder exceptionBuilder = new StringBuilder();
	while (exception != null)
	{
		exceptionBuilder.AppendLine(exception.Message);
		exception = exception.InnerException;
	}
	return exceptionBuilder.ToString();
}

Let’s say you have the following method:

private static void TestExceptionExtension(int divideBy)
{
	try
	{
		int res = 10 / divideBy;
	}
	catch (Exception ex)
	{
		InvalidOperationException ioex = new InvalidOperationException("What are you doing???", ex);
		string errorMessage = string.Concat("Division failed. Tried to divide by ", divideBy);
		throw new ApplicationException(errorMessage, ioex);
	}
}

Call the method as follows and print the exception messages on the console window:

try
{
	TestExceptionExtension(0);
}
catch (Exception ex)
{
	String messages = ex.UserFriendlyFullMessage();
	Console.WriteLine(messages);
}

The output is:

Division failed. Tried to divide by 0
What are you doing???
Attempted to divide by zero.

This is a cleaner presentation of the exceptions to a user who is not familiar with stacktraces and should not even be able to view them.

Enumerations

Consider the following enumeration:

public enum Difficulty
{
	Easy
	, Medium
	, Hard
	, Master
}

We can extend enumerations the same way as other objects. The following extension method will hide the ugly Enum.GetName call behind a friendly method signature:

public static class EnumExtensions
{
	public static string ToUserFriendlyString(this Enum value)
	{
		return Enum.GetName(value.GetType(), value);
	}
}

You can call this extension method on any enumeration:

string val = Difficulty.Easy.ToUserFriendlyString();

You can add an extended description to a specific enum value as follows:

public enum Difficulty
{
	[Description("This is the easy level")]
	Easy
	, Medium
	, Hard
	, Master
}

…where the Description attribute is found in the System.ComponentModel namespace so you’ll need to reference the correct library.

You can read the detailed description using Reflection. We’ll hide the ugly details behind another extension method:

public static string GetDetailedDescription(this Enum value)
{
	FieldInfo fieldInfo = value.GetType().GetField(value.ToUserFriendlyString());
	DescriptionAttribute descriptionAttribute = fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false).FirstOrDefault() as DescriptionAttribute;
	return descriptionAttribute == null ? value.ToUserFriendlyString() : descriptionAttribute.Description;
}

We check if there’s a Description attribute on the enumeration value. If that’s the case then we return the description. Otherwise we’ll use the extension method defined above to return the default value.

You can call these methods as follows:

string val = Difficulty.Easy.ToUserFriendlyString();
string desc = Difficulty.Easy.GetDetailedDescription();

Web API

If Web API doesn’t tell you much then check out its home page. It is a great technology to create RESTful web services. According to RFC 2616, i.e. the HTTP protocol specifications, if a new resource is created with a POST or PUT request then the service should respond with a 201 status code – meaning Created – and a Location header specifying the URL of the newly created resource. Example: “Location: http://api.mysite.com/products/10&#8221;.

It’s customary for Web API controllers to return a HttpResponseMessage object to the client. It can respond with other objects, such as a string, but the HttpResponseMessage object is very rich. You can set the status code, the content body, the HTTP response headers etc.

The solution will therefore extend the HttpResponseMessage object. It will also accept an HttpRequestMessage object which includes the details about the original incoming request. The request is necessary so that we can find the original URI that was used for the POST/PUT operation. We’ll follow the convention that individual resources can be located by an ID parameter in the URL like in the example above: /products/10.

For the solution to work the Controller that processes the POST/PUT request must also be able to process the GET. This is so that URL in the POST/PUT request can be used to extract the URL for the GET in the Location header. Also, the Controller must have a GET method that returns a resource by its id. The following extension method will do the job:

public static void InsertLocationHeader(this HttpResponseMessage httpResponseMessage, 
			HttpRequestMessage httpRequestMessage, int idOfNewResource)
{
	string uri = string.Concat(httpRequestMessage.RequestUri, "/", idOfNewResource);
	httpResponseMessage.Headers.Location = new Uri(uri);
}

We don’t need to return anything from this method. We just take advantage of the fact that objects are reference types and therefore we can modify the state of the httpResponseMessage object we’re extending.

The method can be called as follows:

HttpResponseMessage httpResp = //build the response message;
httpResp.InsertLocationHeader(Request, 20);

The original request can be acquired using the built-in Request property.

Epoch datetime

There’s no built in method in .NET to convert DateTime objects to UNIX timestamps, i.e. to the seconds passed since the midnight of Jan 01 1970. Nothing could be simpler with an extension method:

public static long ToUnixTimeStamp(this DateTime dateTimeUtc)
{
      DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0);
      TimeSpan timeSpan = dateTimeUtc - epoch;
      return Convert.ToInt64(timeSpan.TotalSeconds);
}

We construct a DateTime with the starting point for the Unix timestamp. We get the time span between ‘now’ and the start date. Finally we extract the seconds passed during that time span.

SecureString

The SecureString object can be used to keep confidential text securely in memory. The following extension method will convert a string to a SecureString:

public static SecureString ToSecureString(this string s)
{
        if (s == null)
             return null;

        SecureString psw = new SecureString();
        foreach (char c in s.ToCharArray())
        {
            psw.AppendChar(c);
        }
        return psw;
}

Various

The list of useful extension methods could go on and on. By now you’ve probably got the general idea behind extension methods so you can construct your own. To finish off this short series here’s a couple more methods that you can use in your projects.

Check if integer is within some interval:

public static bool IsBetween(this int theNumber, int lower, int higher)
{
	return (theNumber >= lower) && (theNumber <= higher);
}

Remove some prefix or suffix from a string:

public static string TrimPrefix(this string str, string prefix)
{
        if (!String.IsNullOrEmpty(str) && !String.IsNullOrEmpty(prefix) && str.StartsWith(prefix))
	{
		 return str.Substring(prefix.Length);
	}
	return str;
}

public static string TrimSuffix(this string str, string suffix)
{
        if (!String.IsNullOrEmpty(str) && !String.IsNullOrEmpty(suffix) && str.EndsWith(suffix))
	{
		 return str.Remove(str.Length - suffix.Length);
	}
	return str;
}

Extract the base64 encoded username and password from the Basic Auth header of a HttpRequestMessage object in Web API:

public static Tuple<string, string>
            ExtractUsernameAndPasswordFromHttpHeader(this HttpRequestMessage requestMessage)
{
            Dictionary<string, string> headers = requestMessage.ReadHeaders();
            if (headers.ContainsKey("Authorization"))
            {
                string authHeaderValue = headers["Authorization"];
                authHeaderValue = authHeaderValue.Trim();
                string encodedCredentials = authHeaderValue.Substring(6);
                byte[] decodedBytes = Convert.FromBase64String(encodedCredentials);
                string s = new ASCIIEncoding().GetString(decodedBytes);
                string[] userPass = s.Split(new char[] { ':' });
                string username = userPass[0];
                string password = userPass[1];
                return new Tuple<string, string>(username, password);
            }
            else
            {
                throw new ArgumentNullException("Username and password couldn't be extracted from the HttpHeaders collection.");
            }
}

Extract all headers from a HttpRequestMessage into a Dictionary:

public static Dictionary<string, string>
            ReadHeaders(this HttpRequestMessage requestMessage)
{
      return ExtractHeaders(requestMessage.Headers);
}

private static Dictionary<string, string> ExtractHeaders(HttpHeaders headers)
{
            Dictionary<string, string> dict = new Dictionary<string, string>();
            foreach (var kvp in headers.ToList())
            {
                if (kvp.Value != null)
                {
                    string header = string.Empty;
                    foreach (var j in kvp.Value)
                    {
                        header += j + " ";
                    }
                    dict.Add(kvp.Key, header);
                }
            }
            return dict;
}

Check if an IEnumerable of T is empty:

public static bool IsEmpty<T>(this IEnumerable<T> list)
{
	if (list == null)
		return true;

	if (list is ICollection<T>) 
        	return ((ICollection<T>)list).Count == 0;
	else
		return !list.Any();
}

View all various C# language feature related posts here.

Advertisement

About Andras Nemes
I'm a .NET/Java developer living and working in Stockholm, Sweden.

One Response to Extension methods in C#

  1. Good article but one of the drawback of Extension method is they violate Encapsulation.
    Extension Method in C#
    thanks

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

Elliot Balynn's Blog

A directory of wonderful thoughts

Software Engineering

Web development

Disparate Opinions

Various tidbits

chsakell's Blog

WEB APPLICATION DEVELOPMENT TUTORIALS WITH OPEN-SOURCE PROJECTS

Once Upon a Camayoc

Bite-size insight on Cyber Security for the not too technical.

%d bloggers like this: