Utworzyłem metodę rozszerzenia dla ASP.NET MVC ViewPage, np .:
public static class ViewExtensions
{
public static string Method<T>(this ViewPage<T> page) where T : class
{
return "something";
}
}
Podczas wywoływania tej metody z widoku (pochodzącego z ViewPage
) otrzymuję błąd „ CS0103: Nazwa„ Metoda ”nie istnieje w bieżącym kontekście ”, chyba że użyjęthis
słowa kluczowego, aby ją wywołać:
<%: Method() %> <!-- gives error CS0103 -->
<%: this.Method() %> <!-- works -->
Dlaczego this
wymagane jest słowo kluczowe? A może działa bez niego, ale czegoś mi brakuje?
(Myślę, że musi istnieć duplikat tego pytania, ale nie udało mi się go znaleźć)
Aktualizacja :
Jak mówi Ben Robinson , składnia wywołania metod rozszerzających to po prostu cukier kompilatora. Dlaczego więc kompilator nie może automatycznie sprawdzić metod rozszerzających dla typów podstawowych bieżącego typu bez wymagania słowa kluczowego this?
this
słowo kluczowe), ale pytam, dlaczegothis
słowo kluczowe jest wymagane. Zaktualizowałem moje pytanie.Odpowiedzi:
Kilka punktów:
Po pierwsze, proponowana funkcja (niejawne „this” w wywołaniu metody rozszerzenia) jest niepotrzebna . Metody rozszerzające były niezbędne, aby funkcje składane zapytań LINQ działały tak, jak chcieliśmy; odbiorca jest zawsze określony w zapytaniu, więc nie jest konieczne obsługiwanie tego niejawnego, aby LINQ działał.
Po drugie, ta funkcja działa przeciwko bardziej ogólnemu projektowi metod rozszerzających: a mianowicie, że metody rozszerzające pozwalają rozszerzyć typ, którego nie możesz rozszerzyć samodzielnie , ponieważ jest to interfejs i nie znasz implementacji, lub dlatego, że tak znasz implementację, ale nie masz kodu źródłowego.
Jeśli jesteś w sytuacji, w której używasz metodę rozszerzenia dla typu w tego typu potem nie mieć dostępu do kodu źródłowego. Dlaczego więc w pierwszej kolejności używasz metody rozszerzenia? Możesz napisać metodę instancji jeśli masz dostęp do kodu źródłowego typu rozszerzonego, a następnie nie musisz w ogóle używać metody rozszerzającej! Twoja implementacja może wtedy skorzystać z dostępu do prywatnego stanu obiektu, czego nie mogą uzyskać metody rozszerzające.
Ułatwienie korzystania z metod rozszerzających z poziomu typu, do którego masz dostęp, zachęca do używania metod rozszerzających zamiast metod instancji. Metody rozszerzające są świetne, ale zwykle lepiej jest użyć metody instancji, jeśli taką masz.
Biorąc pod uwagę te dwa punkty, projektant języka nie musi już dłużej wyjaśniać, dlaczego ta funkcja nie istnieje. Teraz musisz wyjaśnić, dlaczego tak się dzieje . Funkcje wiążą się z ogromnymi kosztami. Ta funkcja nie jest konieczna i działa przeciwko określonym celom projektowym metod rozszerzających; dlaczego mielibyśmy ponosić koszty jego wdrożenia? Wyjaśnij, jaki fascynujący, ważny scenariusz umożliwia ta funkcja, a rozważymy jej wdrożenie w przyszłości. Nie widzę żadnego przekonującego, ważnego scenariusza, który to uzasadnia, ale być może jest taki, który przegapiłem.
źródło
this
jest wymagana. 2: Dlaczego wywołuję metodę rozszerzenia z typu rozszerzonego? W podanym przykładzie dodaję kilka wygodnych metod do klasy bazowej (ViewPage) i wzywam ją z klas pochodnych. Eliminuje to potrzebę tworzenia wspólnej klasy bazowej dla wszystkich moich widoków. BTW: Zgadzam się, że użycie metody rozszerzenia z rozszerzonego typu jest niewygodne, ale ponownie zobacz przykład z MVC ViewPage.ICrossProductable
i definiujesz metodę rozszerzającą w tym interfejsie o nazwieGetProduct
. Bardzo prosty przykład, ale często uważam go za przydatny. Nie jest to jednak najlepsze podejście we wszystkich przypadkach.Bez tego kompilator widzi ją jako metodę statyczną w klasie statycznej, która przyjmuje page jako pierwszy parametr. to znaczy
// without 'this' string s = ViewExtensions.Method(page);
vs.
// with 'this' string s = page.Method();
źródło
W metodach instancji wartość „this” jest niejawnie przekazywana do każdej metody w sposób przejrzysty, dzięki czemu można uzyskać dostęp do wszystkich elementów, które udostępnia.
Metody rozszerzające są statyczne. Wywołując
Method()
zamiastthis.Method()
orMethod(this)
, nie mówisz kompilatorowi, co ma przekazać do metody.Możesz powiedzieć „dlaczego po prostu nie zdaje sobie sprawy, czym jest obiekt wywołujący i nie przekazuje tego jako parametru?”.
Odpowiedź jest taka, że metody rozszerzające są statyczne i można je wywołać z kontekstu statycznego, w którym nie ma „tego”.
Wydaje mi się, że mogliby to sprawdzić podczas kompilacji, ale szczerze mówiąc, to prawdopodobnie dużo pracy za wyjątkowo małą zapłatę. Szczerze mówiąc, widzę niewielką korzyść w pozbyciu się niektórych jawności wywołań metod rozszerzających. Fakt, że można je pomylić na przykład z metodami, oznacza, że czasami mogą być dość nieintuicyjne (na przykład NullReferenceExceptions nie są zgłaszane). Czasami myślę, że powinni byli wprowadzić nowy operator typu „potok do przodu” dla metod rozszerzających.
źródło
Należy zauważyć, że istnieją różnice między metodami rozszerzającymi a zwykłymi metodami. Myślę, że właśnie spotkałeś jedną z nich.
Podam przykład innej różnicy: dość łatwo jest wywołać metodę rozszerzającą w
null
odniesieniu do obiektu. Na szczęście jest to o wiele trudniejsze przy zwykłych metodach. (Ale można to zrobić. IIRC, Jon Skeet zademonstrował, jak to zrobić, manipulując kodem CIL).static void ExtensionMethod(this object obj) { ... } object nullObj = null; nullObj.ExtensionMethod(); // will succeed without a NullReferenceException!
Biorąc to pod uwagę, zgadzam się, że wydaje się to trochę nielogiczne
this
wywołanie metody rozszerzenia . W końcu metoda rozszerzająca powinna idealnie „czuć” i zachowywać się jak normalna.Ale w rzeczywistości metody rozszerzeń są bardziej jak cukier składniowy dodawany do istniejącego języka niż wczesna podstawowa funkcja, która dobrze pasuje do języka pod każdym względem.
źródło
null
? Może to być dowolny typ referencyjny, skąd wie, jakie metody są dostępnenull
?String
logicznie zachowują się jak wartości, i mogą mieć rozsądną wartość domyślną, gdy null (np. .Net może konsekwentnie traktować zerową referencję typu statycznegostring
jako pusty ciąg, zamiast robić to sporadycznie). Konieczność używania statycznych metod do takich rzeczyif (!String.IsNullOrEmpty(stringVar))
jest po prostu ohydna.Ponieważ metoda rozszerzenia nie istnieje w klasie ViewPage. Musisz powiedzieć kompilatorowi, do czego wywołujesz metodę rozszerzenia. Pamiętaj, że
this.Method()
to tylko cukier kompilatoraViewExtensions.Method(this)
. W ten sam sposób nie można po prostu wywołać metody rozszerzającej w środku dowolnej klasy za pomocą nazwy metody.źródło
this
słowa kluczowego?Pracuję nad płynnym API i napotkałem ten sam problem. Mimo że mam dostęp do rozszerzanej klasy, nadal chciałem, aby logika każdej z metod Fluent znajdowała się we własnych plikach. Słowo kluczowe „this” było bardzo nieintuicyjne, użytkownicy wciąż myśleli, że brakuje metody. To, co zrobiłem, to uczynienie mojej klasy częściową klasą, która implementuje metody, których potrzebowałem, zamiast używać metod rozszerzających. W odpowiedziach nie było wzmianki o częściach podrzędnych. Jeśli masz to pytanie, częściowe mogą być lepszą opcją.
źródło