I ran into something at work involving a conversion routine that I had written about a year ago that takes a list of a type and converts it into a string. Today I had a new class with very similar fields that I needed to run the same coversion on. I was able to work it out in C# 3, but not quite in an ideal way. To do it the right way I’d have to be using C# 4 because if its support for covarance in interfaces, which, as it turns out, makes extension methods much more useful.
Here’s a (rather silly) example that demonstrates a situation similar to mine:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace CovariantExtensionMethods { public interface IMyInterface { string Value { get; set; } } public class MyClass : IMyInterface { public string Value { get; set; } } public class MyOtherClass : IMyInterface { public string Value { get; set; } } public static class MyExtensions { public static string ConvertStuff(this IEnumerable<IMyInterface> stuff) { return string.Join(", ", stuff.Select(s => s.Value)); } } class Program { static void Main(string[] args) { List<MyClass> mine = new List<MyClass> { new MyClass { Value = "One" }, new MyClass { Value = "Two" }, new MyClass { Value = "Three" }, }; List<MyOtherClass> mine2 = new List<MyOtherClass> { new MyOtherClass { Value = "One" }, new MyOtherClass { Value = "Two" }, new MyOtherClass { Value = "Three" }, }; Console.WriteLine(mine.ConvertStuff()); Console.WriteLine(mine2.ConvertStuff()); } } }
So what’s going on here? First, I have an interface, IMyInterface, that defines a single property, Value, and a class that implements that interface. Then I have an extension method, ConvertStuff, that takes an IEnumerable<IMyInterface>. In the Main method I then have a List<MyClass>, and a List<MyOtherClass>, and I call the ConvertStuff extension method on both lists – even though they are lists of different types!
In the past, this extension method would have only shown up on a variable typed as an IEnumerable<IMyInterface> (or one of its subclasses, such as List<IMyInteface>), but not on List<MyClass>, but because in .NET 4 IEnumerable now supports covariance (its definition is IEnumerable<out T>) my extension method will show up on any class that implements IEnumerable<[IMyInterface or any of its implementations]>. This is very similar to what you’d see in Java as IEnumerable<? implements IMyInterface>, but it just happens automatically in C# 4 because the covariance is defined by the writer of the type, and not the consumer.
This makes extension methods much more versatile, and is a very welcome addition to C#.
Thanks Microsoft!
