Jestem fanem metod rozszerzenia w języku C #, ale nie udało mi się dodać metody rozszerzenia do klasy statycznej, takiej jak konsola.
Na przykład, jeśli chcę dodać rozszerzenie do konsoli o nazwie „WriteBlueLine”, aby móc przejść:
Console.WriteBlueLine("This text is blue");
Próbowałem tego, dodając lokalną, publiczną metodę statyczną, z konsolą jako parametrem „to” ... ale żadnych kości!
public static class Helpers {
public static void WriteBlueLine(this Console c, string text)
{
Console.ForegroundColor = ConsoleColor.Blue;
Console.WriteLine(text);
Console.ResetColor();
}
}
Nie dodało to metody „WriteBlueLine” do konsoli ... czy robię to źle? Czy prosić o niemożliwe?
c#
static
extension-methods
Leon Bambrick
źródło
źródło
Helpers.WriteBlueLine(null, "Hi");
:)Odpowiedzi:
Nie. Metody rozszerzenia wymagają zmiennej obiektu (wartości) dla obiektu. Możesz jednak napisać statyczne opakowanie wokół
ConfigurationManager
interfejsu. Jeśli zaimplementujesz opakowanie, nie potrzebujesz metody rozszerzenia, ponieważ możesz po prostu dodać metodę bezpośrednio.źródło
Czy możesz dodać statyczne rozszerzenia do klas w języku C #? Nie, ale możesz to zrobić:
Oto jak to działa. Chociaż technicznie nie można pisać statycznych metod rozszerzenia, ten kod wykorzystuje lukę w metodach rozszerzenia. Ta luka polega na tym, że możesz wywoływać metody rozszerzenia na obiektach zerowych bez uzyskania wyjątku zerowego (chyba że uzyskasz dostęp do czegokolwiek za pośrednictwem @ tego).
Oto, jak byś tego użył:
DLACZEGO dlaczego wybrałem jako przykład wywoływanie domyślnego konstruktora i ORAZ dlaczego po prostu nie zwracam nowej T () w pierwszym fragmencie kodu bez robienia wszystkich śmieci z wyrażeń? Cóż, dziś masz szczęśliwy dzień, bo dostajesz 2fer. Jak wie każdy zaawansowany programista .NET, nowa funkcja T () działa powoli, ponieważ generuje wywołanie do System.Activator, który używa odbicia, aby uzyskać domyślny konstruktor przed wywołaniem go. Cholera, Microsoft! Jednak mój kod wywołuje bezpośrednio domyślny konstruktor obiektu.
Rozszerzenia statyczne byłyby lepsze od tego, ale desperackie czasy wymagają desperackich środków.
źródło
XConsole
,ConsoleHelper
i tak dalej.(null as DataSet).Create();
może byćdefault(DataSet).Create();
.To nie jest możliwe.
I tak, myślę, że stwardnienie rozsiane popełniło tutaj błąd.
Ich decyzja nie ma sensu i zmusza programistów do napisania (jak opisano powyżej) bezsensownej klasy opakowania.
Oto dobry przykład: Próba rozszerzenia statycznej klasy testowania MS Unit Assert: Chcę jeszcze 1 metodę Assert
AreEqual(x1,x2)
.Jedynym sposobem na to jest wskazanie różnych klas lub napisanie opakowania wokół setek różnych metod Assert. Dlaczego!?
Jeśli podjęto decyzję o zezwoleniu na rozszerzenia instancji, nie widzę logicznego powodu, aby nie zezwalać na rozszerzenia statyczne. Argumenty o bibliotekach sekcyjnych nie stoją po rozszerzeniu instancji.
źródło
Assert.Throws
odpowiedzieć stackoverflow.com/questions/113395/…Natknąłem się na ten wątek, próbując znaleźć odpowiedź na to samo pytanie, jakie miał OP. Nie znalazłem odpowiedzi, której chciałem, ale ostatecznie to zrobiłem.
I używam tego w ten sposób:
źródło
Być może możesz dodać klasę statyczną z niestandardową przestrzenią nazw i tą samą nazwą klasy:
źródło
Począwszy od wersji C # 7 nie jest to obsługiwane. Trwają jednak dyskusje na temat włączenia czegoś takiego w C # 8 i propozycji wartych poparcia .
źródło
Nie. Definicje metod rozszerzenia wymagają wystąpienia rozszerzanego typu. To niefortunne; Nie jestem pewien, dlaczego jest to wymagane ...
źródło
Jeśli chodzi o metody rozszerzenia, same metody rozszerzenia są statyczne; ale są wywoływane tak, jakby były metodami instancji. Ponieważ klasa statyczna nie jest możliwa do utworzenia, nigdy nie będzie instancji klasy, z której można by wywołać metodę rozszerzenia. Z tego powodu kompilator nie zezwala na definiowanie metod rozszerzeń dla klas statycznych.
Pan Obnoxious napisał: „Jak wie każdy zaawansowany programista .NET, nowa T () działa wolno, ponieważ generuje wywołanie do System.Activator, który używa odbicia, aby uzyskać domyślny konstruktor przed wywołaniem go”.
New () jest kompilowany do instrukcji IL „newobj”, jeśli typ jest znany w czasie kompilacji. Newobj pobiera konstruktora do bezpośredniego wywoływania. Wywołania System.Activator.CreateInstance () kompilują się z instrukcją IL „call” w celu wywołania System.Activator.CreateInstance (). Funkcja New () zastosowana wobec typów ogólnych spowoduje wywołanie funkcji System.Activator.CreateInstance (). Wpis pana Obnoxiousa był niejasny w tej kwestii ... i cóż, wstrętny.
Ten kod:
produkuje tę IL:
źródło
Nie możesz dodać statycznego metod do typu. Można dodawać tylko metody (pseudo) instancji do instancji typu.
Celem
this
modyfikatora jest poinformowanie kompilatora C #, aby przekazał instancję po lewej stronie.
jako pierwszy parametr metody static / extension.W przypadku dodawania metod statycznych do typu nie ma instancji do przekazania dla pierwszego parametru.
źródło
Próbowałem to zrobić za pomocą System.Environment, kiedy uczyłem się metod rozszerzania i nie powiodło się. Powodem jest, jak wspominają inni, ponieważ metody rozszerzenia wymagają wystąpienia klasy.
źródło
Nie można napisać metody rozszerzenia, jednak można naśladować zachowanie, o które prosisz.
Umożliwi to wywołanie Console.WriteBlueLine (fooText) w innych klasach. Jeśli inne klasy chcą uzyskać dostęp do innych statycznych funkcji konsoli, będą musiały zostać jawnie przywołane poprzez ich przestrzeń nazw.
Zawsze możesz dodać wszystkie metody do klasy zastępczej, jeśli chcesz mieć je wszystkie w jednym miejscu.
Więc miałbyś coś takiego
Zapewniłoby to rodzaj zachowania, którego szukasz.
* Uwaga: Konsola będzie musiała zostać dodana poprzez przestrzeń nazw, w której została umieszczona.
źródło
tak, w ograniczonym sensie.
To działa, ale konsola nie działa, ponieważ jest statyczna.
Działa to, o ile nie znajduje się w tej samej przestrzeni nazw. Problem polega na tym, że musisz napisać statyczną metodę proxy dla każdej metody, jaką posiada System.Console. To niekoniecznie zła rzecz, ponieważ możesz dodać coś takiego:
lub
Działa to tak, że podpinasz coś do standardowej linii WriteLine. Może to być liczba wierszy, filtr niepoprawnych słów lub cokolwiek innego. Ilekroć po prostu określisz konsolę w przestrzeni nazw, powiedz WebProject1 i zaimportuj przestrzeń nazw System, WebProject1.Console zostanie wybrana zamiast System.Console jako domyślna dla tych klas w przestrzeni nazw WebProject1. Tak więc ten kod zmieni wszystkie wywołania Console.WriteLine w niebieskie, o ile nigdy nie podano System.Console.WriteLine.
źródło
Poniższe zostało odrzucone jako edycja odpowiedzi tvanfosson. Poproszono mnie o udzielenie odpowiedzi jako mojej własnej odpowiedzi. Skorzystałem z jego sugestii i zakończyłem implementację
ConfigurationManager
opakowania. Zasadniczo po prostu wypełniłem odpowiedź...
w tvanfosson.źródło
Możesz użyć rzutowania na wartość NULL, aby działało.
Rozszerzenie:
Twój typ:
źródło
Możesz to zrobić, jeśli zechcesz trochę „fregować”, tworząc zmienną klasy statycznej i przypisując jej wartość null. Jednak ta metoda nie byłaby dostępna dla wywołań statycznych w klasie, więc nie jestem pewien, ile by to wykorzystało:
źródło