10 More Useful C# Extension Methods for 2019
The Third Annual C# Advent Calendar is underway and, this year, I continue the tradition with 10 more C# Extension Methods for the stocking!
Note: Usually, I post on Mondays, Wednesdays, or Fridays, but I selected a date from the Advent calendar that fell on a Sunday making this post an exception.
It's that time of year again for the Third Annual C# Advent. For those who never heard of it, the C# Advent contains 25 days of C# content all leading up to Christmas.
Initially, the advent had one post per day. However, this year, Matt Groves is carrying on the tradition of 2 posts per day. So that's double the content for half the price. ;-)
Since I've accumulated more extension methods over the past year (and it's becoming my tradition of extension methods from 2017 and 2018), I thought I'd continue with these small "stocking stuffer" extension methods.
It's also the season for "extensions" anyway (i.e. extension cords).
GetDomain()
How many times have you absolutely needed the domain name of your site?
This little gem extends the HttpContextBase and HttpContext to provide the domain name of your site.
public static class HttpContextExtensions { public static string GetDomain(this HttpContext context) { return context.Request.Url.GetLeftPart(UriPartial.Authority); }
public static string GetDomain(this HttpContextBase context) { return context.Request.Url.GetLeftPart(UriPartial.Authority); } }
Usage:
var host = HttpContext.Current.GetDomain();
ChunkBy()
For this particular extension, I needed to breakdown a list into smaller lists, so I needed 5 lists of 10 items.
Instead of using a for..next loop, I attached an extension method to a List and passed in the grouping size.
Consider it like a paging function for lists and arrays.
public static class ListExtensions { public static List<List<T>> ChunkBy<T>(this List<T> source, int chunkSize) { return source .Select((x, i) => new { Index = i, Value = x }) .GroupBy(x => x.Index / chunkSize) .Select(x => x.Select(v => v.Value).ToList()) .ToList(); } }
Usage:
var newList = products.ChunkBy(10);
ToYesNo()
Yes, I know what you're thinking. Why create an extension method displaying a Yes/No when you can easily create a simple ternary expression in your HTML? (i.e. product.IsEnabled ? "Yes" : "No"
)
Because I like to keep the HTML clean with no "business logic" in my presentation layer.
public static class BoolExtensions { public static MvcHtmlString ToYesNo(this bool value) { const string text = "<div class=\"text-center\">{0}</div>"; return value ? MvcHtmlString.Create(String.Format(text, "Yes")) : MvcHtmlString.Create(String.Format(text, "No")); } }
Usage:
@Html.Raw(model.Enabled.ToYesNo())
GetDatesArray()
This extension method takes a start and end date and returns a list of those dates in an array.
public static DateTime[] GetDatesArray(this DateTime fromDate, DateTime toDate) { int days = (toDate - fromDate).Days; var dates = new DateTime[days];
for (int i = 0; i < days; i++) { dates[i] = fromDate.AddDays(i); }
return dates; }
Usage:
var startDate = new DateTime(2019,12,15);
var endDate = new DateTime(2019,12,25);
var dates = startDate.GetDatesArray(endDate);
ToDataTable()
Looking for a quick and dirty way to create a DataTable from a list of items?
I got ya covered.
This extension method takes an IList and each object's properties and converts the properties into fields and places the data into a datatable.
public static DataTable ToDataTable<T>(this IList<T> items) { var tb = new DataTable(typeof(T).Name);
PropertyInfo[] props = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (PropertyInfo prop in props) { Type t = GetCoreType(prop.PropertyType); tb.Columns.Add(prop.Name, t); }
foreach (T item in items) { var values = new object[props.Length]; for (int i = 0; i < props.Length; i++) { values[i] = props[i].GetValue(item, null); }
tb.Rows.Add(values); }
return tb; }
Usage:
var table = products.ToDataTable();
GetResources()
I use Resource Files a lot for internationalization, database seeding, and database mocking.
Why not just immediately pull the resources and save them for later?
GetResources() returns back a dictionary of the string names with their contents. Use the dictionary key to access the resource.
public static class ResourceExtensions { public static Dictionary<string, object> GetResources(this ResourceManager manager, string culture="") { culture = String.IsNullOrEmpty(culture) ? "en" : culture; var resources = manager.GetResourceSet(new System.Globalization.CultureInfo(culture), true, true);
var resourceStringList = new List<string>(); var iterator = resources.GetEnumerator(); while (iterator.MoveNext()) resourceStringList.Add(iterator.Key.ToString());
return resourceStringList.ToDictionary(s => s, manager.GetItem); }
private static object GetItem(this ResourceManager manager, string resource) { return manager.GetObject(resource); } }
Usage:
var resourceManager = new ResourceManager("DefaultData", Assembly.GetExecutingAssembly() );
var resourceList = resourceManager.GetResources();
ToByteArray()
Looking to convert an image into a bytearray to store in a database?
public static byte[] ToByteArray(this Image imageIn) { var ms = new MemoryStream(); imageIn.Save(ms, System.Drawing.Imaging.ImageFormat.Png); return ms.ToArray(); }
Usage:
var bytes = image.ToByteArray();
ToImage()
You didn't think I wouldn't tell you how to retrieve it, did you?
public static Image ToImage(this byte[] data) { var ic = new ImageConverter(); var img = (Image)ic.ConvertFrom(data); return img; }
Usage:
var image = byteArray.ToImage();
ToJson<T>()
This extension method is the most compact and most used throughout my applications.
Want to create a quick Json representation of an object? Use .ToJson(). This extension method requires Newtonsoft's JsonSerializer.
How's that for compact?
public static string ToJson<T>(this T instance) => JsonConvert.SerializeObject(instance, JsonSettings.SerializerDefaults);
Usage:
var json = address.ToJson();
To<T>()
Again, you didn't think I would leave you high and dry with a Json string, did you?
To<T> transforms the Json string back into a C# object.
public static T To<T>(this string json) => JsonConvert.DeserializeObject<T>(json, JsonSettings.SerializerDefaults);
Usage:
var address = json.To<Address>();
Note: You may have noticed the JsonSettings.SerializerDefaults in the DeserializeObject method. I created a static JsonSettings defaults file to keep them in a centralized location.
public static class JsonSettings { static readonly DefaultContractResolver _contractResolver = new DefaultContractResolver { NamingStrategy = new CamelCaseNamingStrategy() };
internal static JsonSerializerSettings SerializerDefaults { get; } = new JsonSerializerSettings { DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate, ContractResolver = _contractResolver, Formatting = Formatting.Indented, NullValueHandling = NullValueHandling.Ignore }; }
Conclusion
Extension Methods are great for taking your code further and making it even easier to use in your applications. The best part is you can even have your own business jargon as part of the methods which I feel is encouraged to provide a better explanation of your code.
Make sure you visit the Third Annual C# Advent Calendar. The amount of C# on this one page is staggering. It will definitely satisfy the C# part of your brain.
Thanks again to Matt Groves for an awesome "carnival" of C# and to the awesome authors as well. So much great stuff.
Happy Holidays!
What are your favorite extension methods? Do you have one? Do you care? ;-) Post your comments below and let's discuss.