Yan Cui
I help clients go faster for less using serverless technologies.
This article is brought to you by
I never fully recovered my workspace setup when I upgraded my laptop two years ago, and I still miss things today. If only I had known about Gitpod back then…
I saw an interesting use of covariance today, consider an interface IMyClass and an implementing class MyClass:
1: public interface IMyClass { }
2:
3: public class MyClass : IMyClass { }
If you want to convert an List<MyClass> to a List<IMyClass> you would normally use the Enumerable.Cast method but did you know that you can also use C# 4’s support for covariance in the type parameter and do this instead:
1: var original = new List<MyClass>();
2:
3: var converted = original.ToList<IMyClass>()
Funky, eh? ;-)
Though I think it’s a party trick best avoided for any production code, for which you should still prefer:
1: var converted = original.Cast<IMyClass>().ToList();
because:-
- it achieves the same result
- it is just as expressive
- it is the standard way of doing this kind of conversions in LINQ
- it is understood by most C# developers so unlikely to cause confusion
There’s another argument for using Cast, in the case of use-defined implicit/explicit operators. Imagine if you have another class which does not inherit from MyClass but defines an explicit operator which allows you to cast an instance of MyClass:
1: public class MyOtherClass
2: {
3: public static explicit operator MyClass(MyOtherClass other)
4: {
5: return new MyClass();
6: }
7: }
In cases like this, you won’t be able to use the covariance trick:
1: void Main()
2: {
3: var original = new List<MyClass>();
4:
5: Console.WriteLine(original.GetType()); // List<MyClass>
6:
7: // cast here doesn't actually do anything
8: Console.WriteLine(original.Cast<IMyClass>().ToList().GetType()); // List<IMyClass>
9:
10: // changes the compile type, works because of covariance
11: Console.WriteLine(original.ToList<IMyClass>().GetType()); // List<IMyClass>
12:
13: // casts the objs to MyOtherClass using the defined convertor
14: Console.WriteLine(original.Cast<MyOtherClass>().ToList().GetType()); // List<MyOtherClass>
15:
16: // this line won't compile.
17: // it doesn't work because this is not covariance, there's no inheritance
18: // relationship between MyClass and MyOtherClass
19: // Console.WriteLine(objs.ToList<MyOtherClass>().GetType());
20: }
References:
StackOverflow question – Casting List<T> – covariance/contravariance problem
Whenever you’re ready, here are 3 ways I can help you:
- Production-Ready Serverless: Join 20+ AWS Heroes & Community Builders and 1000+ other students in levelling up your serverless game. This is your one-stop shop for quickly levelling up your serverless skills.
- I help clients launch product ideas, improve their development processes and upskill their teams. If you’d like to work together, then let’s get in touch.
- Join my community on Discord, ask questions, and join the discussion on all things AWS and Serverless.