Last active
April 11, 2019 10:39
-
-
Save lrhn/214bb4e86d5c3621b8df5fb42046e31a to your computer and use it in GitHub Desktop.
Example of Extension Method Resolution
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// C# has invariant generics, so only `b.Copy()` matches the `Bar.Copy` method. | |
// It's unsurprising that the other two use Foo. | |
// For the conflict, C# prefers the non-generic function over the generic one. | |
// That's also true for normal static class. | |
using System; | |
using System.Collections.Generic; | |
public class Program | |
{ | |
public static void Main() | |
{ | |
List<A> a = new List<A>() { new A() }; | |
List<B> b = new List<B>() { new B() }; | |
List<C> c = new List<C>() { new C() }; | |
a.Copy(false); // Gen | |
b.Copy(false); // Spc | |
c.Copy(false); // Gen | |
Test(a); // TestGen | |
Test(b); // TestSpc | |
Test(c); // TestGen | |
} | |
static List<T> Test<T>(List<T> self) { | |
Console.WriteLine("TestGen"); | |
return self; | |
} | |
static List<B> Test(List<B> self) { | |
Console.WriteLine("TestSpc"); | |
return self; | |
} | |
} | |
static class Foo { | |
public static List<T> Copy<T>(this List<T> self, bool reversed) { | |
Console.WriteLine("Gen"); | |
List<T> result = new List<T>(); | |
foreach (var v in self) { | |
if (reversed) { | |
result.Insert(0, v); | |
} else { | |
result.Add(v); | |
} | |
} | |
return result; | |
} | |
} | |
static class Bar { | |
public static List<B> Copy(this List<B> self, bool reversed) { | |
Console.WriteLine("Spc"); | |
List<B> result = new List<B>(); | |
foreach (var v in self) { | |
if (reversed) { | |
result.Insert(0, v); | |
} else { | |
result.Add(v); | |
} | |
} | |
return result; | |
} | |
} | |
class A {} | |
class B : A {} | |
class C : B {} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Prefers specific type over generic where both apply. | |
// Same resolution as fo static method overloading. | |
fun main() { | |
var a : List<A> = listOf<A>(A()); | |
var b : List<B> = listOf<B>(B()); | |
var c : List<C> = listOf<C>(C()); | |
a.copy().isGen(); // Gen | |
b.copy().isSpc(); // Spc | |
c.copy().isSpc(); // Spc | |
test(a).isGen(); // TestGen | |
test(b).isSpc(); // TestSpc | |
test(c).isSpc(); // TestSpc | |
} | |
fun <T> test(x: List<T> ) : Gen { | |
println("TestGen"); | |
return Gen(); | |
} | |
fun test(x: List<B>) : Spc { | |
println("TestSpc"); | |
return Spc(); | |
} | |
// Cannot have same return type as List<T>.copy, after erasure, they have same signature. | |
fun List<B>.copy() : Spc { | |
println("Spc"); | |
return Spc(); | |
} | |
fun <T> List<T>.copy() : Gen { | |
println("Gen"); | |
return Gen(); | |
} | |
class Spc { | |
fun isSpc() {} | |
} | |
class Gen { | |
fun isGen() {} | |
} | |
open class A() {} | |
open class B() : A() {} | |
open class C() : B() {} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment