Zine.net online

Witaj na Zine.net online Zaloguj się | Rejestracja | Pomoc
w Szukaj

mgrzeg.net - Admin on Rails :)

C# 3.0: Metody rozszerzeń - garść szczegółów

W C# 3.0 pojawiają się nowe konstrukcje językowe, między innymi tzw. metody rozszerzeń (Extension Methods). Bez większego rozwodzenia się, poniżej krótki przykład.
using System;
namespace TestExtMethods
{
  class Program
  {
    static void Main(string[] args)
    {
      "kot".TestExt();
    }
  }
  public static class Extensions
  {
    public static string TestExt(this string ala)
    {
      return string.Format("testExt: {0}", ala);
    }
  }
}

Wygląda na to, że metoda TestExt rozszerza nam wbudowaną klasę System.String. Nie jest to metoda ‘zaprzyjaźniona’ z dostępem do składowych prywatnych klasy string, właściwie poza słowem kluczowym ‘this’ pojawiającym się na liście argumentów metody niczym nie różni się od zwykłej metody statycznej. Czyżby?
Gdy zajrzymy do kodu IL wygenerowanego przez kompilator, wszystko staje się jasne. W rzeczywistości metody rozszerzeń są zwykłymi metodami statycznymi z dodatkowym atrybutem ‘znacznikiem’ dla intellisense i kompilatora (Reflector również potrafi ten atrybut właściwie zinterpretować):
[System.Runtime.CompilerServices.Extension]
    public static string TestExt(string ala)
    {
      return string.Format("testExt: {0}", ala);
    }


W rzeczywistości, przy próbie dodania takiego atrybutu do metody statycznej otrzymujemy błąd kompilacji CS1112: "Do not use 'System.Runtime.CompilerServices.ExtensionAttribute'. Use the 'this' keyword instead."

Czy ta wiedza coś nam daje?
Skoro metody rozszerzeń to zwykłe metody statyczne statycznych klas, to możemy wywoływać je jak każde inne. Tym samym, jeśli ktoś dostarczył nam bibliotekę zawierającą metody rozszerzeń o takich samych nazwach jak te, które my zdefiniowaliśmy w swoich modułach, to żeby uniknąć błędu kompilacji ‘The call is ambiguous...’, który pojawi się, jeśli będziemy mieli w kontekście dwie klasy statyczne definiujące metody rozszerzeń o tej samej nazwie, możemy wywoływać bezpośrednio odpowiednie metody rozszerzeń, informując tym samym kompilator, o którą metodę nam chodzi:
static void Main(string[] args)
    {
      Extensions.TestExt("kot");
    }

i unikając tym samym błędu kompilacji. Co ciekawe, Reflector znowuż zinterpretuje powyższe wywołanie jako użycie metody rozszerzeń i w podglądzie C# znowuż dostajemy ""kot".TestExt();"

Opublikowane 10 lipca 2007 12:37 przez mgrzeg
Filed under: ,

Powiadamianie o komentarzach

Jeżeli chciałbyś otrzymywać email gdy ta wypowiedź zostanie zaktualizowana, to zarejestruj się tutaj

Subskrybuj komentarze za pomocą RSS

Komentarze:

 

ucel said:

Uprzedziles mnie :). W ramach nastepnej porcji "wolnego czasu" mialem wlasnie sprawdzic jak to dziala :)

lipca 10, 2007 16:53
 

Tarciu said:

Ciekawe, bo dotąd np. przy przeciążaniu operatorów czy definiowaniu własnego rzutowania istniało ograniczenie, że dany operator może być zdefiniowany tylko w klasie, której dotyczy.

Tłumaczono to względami wydajnościowymi - inaczej trzeba by przeszukiwać zbyt wiele klas w poszukiwaniu przeciążonego operatora.

Tymczasem w przypadku metod rozszerzeń, taka metoda może się znajdować w dowolnej klasie i dotyczyć dowolnego typu. Czyżby komputery były już wystarczająco szybkie? ;)

lipca 11, 2007 08:24

Co o tym myślisz?

(wymagane) 
(opcjonalne)
(wymagane) 

  
Wprowadź kod: (wymagane)
Wyślij
W oparciu o Community Server (Personal Edition), Telligent Systems