Интересно, я ожидал от компилятора C# в таком коде скрытого замыкания:

static class Foo {
  static void Bar(this string source) { }
  static void Main() {
    System.Action boo = "abc".Bar;
  }
}

На самом деле компилятор сгенерировал здесь точно такой же msil, как если бы метод Bar() был настоящим методом уровня экземпляра типа System.String, сохранив экземпляр строки в экземпляре делегата - так же, как сохраняет и автоматически “подставляет” в качестве первого параметра скрытый от пользователя this.

Было бы интересно иметь противоположную возможность - позволить создавать из методов уровня экземпляра делегаты с произвольным this-параметром, допустив указание произвольного экземплярного метода без экземпляра соответствующего типа (и даже нет проблем пересечения с именами статических методов):

System.Func<string, int> boo = System.String.Length;

Однако очевидная проблема данной фичи проявляется в случае использования виртуальных методов:

System.Func<Foo, int> boo = Foo.GetHashCode;

Из какого именно метода делать делегат? Из метода Foo.GetHashCode()? Что, если тип Foo не переопределяет метод GetHashCode() - брать реализацию Object.GetHashCode? Что, если первым параметром делегата передадут наследника Foo, имеющего свою реализацию GetHashCode() - вызывать эту реализацию (тогда делегат никогда не будет указывать на какой-то конкретный метод) или использовать реализацию типа Foo (что позволяет на наследниках вызовы Foo.GetHashCode(), которые могут быть недопустимы)? Допускать-ли такую запись, если метод GetHashCode() объявлен абстрактным? Кстати, Object.GetHashCode(), как и любой другой виртуальный метод, можно переопределить и одновременно сделать абстрактным, путём комбинирования модификаторов abstract и override - что делать в таком случае?

Вообщем, мягко говоря, сомнительная фича получается :)