I saw Jon Skeet's lecture at the NDC 2010
He mentioned something interesting :
public Class Base
{
public void Foo(IEnumerable<string> strings){}
}
public Class Child:Base
{
publc void Foo(IEnumerable<object> objects) {}
}
Main :
List<string> lst = new List<string>();
lst.Add("aaa");
Child c = new Child();
c.Foo(lst);
With C# 3 it will call : Base.Foo
With C# 4 it will call : Child.Foo
I know it's because covariance
Question :
Isn't it a bit code breaking change ? Is there any workaround so this code will continue work as it was on ver 3?
Yes, it's a breaking change. Any time you make a prevously-invalid conversion legal, it's a breaking change.
Unfortunately, it's very hard to add features to the language without making any breaking changes. There are a few more around events in C# 4 if you really want to look for them. It's unlikely that these will affect most developers, of course.
There were similar breaking changes between C# 1 and C# 2, where the implementation used would have changed between different versions for this code:
using System;
public delegate void StringAction(string x);
public class Base
{
public void Foo(string x)
{
Console.WriteLine("Base");
}
}
public class Child : Base
{
public void Foo(object x)
{
Console.WriteLine("Child");
}
}
public class Test
{
static void Main()
{
Child c = new Child();
StringAction action = new StringAction(c.Foo);
action("x");
}
}
In this case the compiler actually gives a warning:
Test.cs(26,31): warning CS1707: Delegate 'StringAction' bound to
'Child.Foo(object)' instead of 'Base.Foo(string)' because of new
language rules
Jon is of course right; it is a breaking change. An even easier way to see that breaking change is:
object x = new List<string>();
if (x is IEnumerable<object>)
Console.WriteLine(4);
else
Console.WriteLine(3);
In C# 3 that prints 3; in C# 4 it prints 4.
When you change the type system, you change the results of overload resolution; that's just how it goes. The benefit of the feature outweighs the pain of the possible breaks.
Is there a workaround? Yes. Don't call Child.Foo in the first place:
Base c = new Child();
c.Foo(list);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With