Patrzę na składnik MvcContrib Grid i jestem zafascynowany, ale jednocześnie odparty, przez sztuczkę składniową zastosowaną w składni Grid :
.Attributes(style => "width:100%")
Powyższa składnia ustawia atrybut stylu wygenerowanego HTML na width:100%
. Teraz, jeśli zwrócisz uwagę, „styl” nigdzie nie jest określony, wywnioskuje się z nazwy parametru w wyrażeniu! Musiałem się w to zagłębić i odkryłem, gdzie dzieje się „magia”:
Hash(params Func<object, TValue>[] hash)
{
foreach (var func in hash)
{
Add(func.Method.GetParameters()[0].Name, func(null));
}
}
W rzeczy samej, kod używa formalnej, czas kompilacji, nazwy parametrów do stworzenia słownika par nazwa-wartość atrybutu. Wynikowa konstrukcja składni jest rzeczywiście bardzo ekspresyjna, ale jednocześnie bardzo niebezpieczna. Ogólne użycie wyrażeń lambda pozwala na zastąpienie używanych nazw bez skutków ubocznych. Widzę przykład w książce, który mówi, collection.ForEach(book => Fire.Burn(book))
że wiem, że mogę pisać w moim kodzie, collection.ForEach(log => Fire.Burn(log))
a to oznacza to samo . Ale dzięki składni MvcContrib Grid nagle znajduję kod, który aktywnie wyszukuje i podejmuje decyzje na podstawie nazw wybranych dla moich zmiennych!
Czy więc jest to powszechna praktyka w społeczności C # 3.5 / 4.0 i miłośnikach wyrażeń lambda? A może jest nieuczciwym indywidualistą, którego nie powinienem się martwić?
źródło
Odpowiedzi:
To ma słabą interop. Weźmy na przykład ten przykład w C # - F #
DO#:
FA#:
Wynik:
Drukowane jest „arg” (nie „yadda”).
W rezultacie projektanci bibliotek powinni albo unikać tego rodzaju „nadużyć”, albo przynajmniej zapewniać „standardowe” przeciążenie (np. Traktuje nazwę łańcucha jako dodatkowy parametr), jeśli chcą mieć dobrą współpracę między językami .Net.
źródło
Uważam to za dziwne nie tyle z powodu imienia , ale dlatego, że lambda jest niepotrzebna ; mógłby użyć typu anonimowego i być bardziej elastyczny:
Jest to wzorzec używany w większości ASP.NET MVC (na przykład) i ma inne zastosowania ( zastrzeżenie , zwróć uwagę również na myśli Ayende, jeśli nazwa jest wartością magiczną, a nie specyficzną dla dzwoniącego)
źródło
HtmlAttributes
klasę z oczekiwanymi atrybutami (dla inteligencji) i po prostu zignoruj te znull
wartościami ...Chciałem tylko wrzucić moją opinię (jestem autorem komponentu siatki MvcContrib).
To zdecydowanie nadużycie językowe - bez wątpienia. Jednak tak naprawdę nie uważałbym tego za sprzeczne z intuicją - kiedy spojrzysz na połączenie z
Attributes(style => "width:100%", @class => "foo")
, myślę, że to całkiem oczywiste, co się dzieje (z pewnością nie jest gorsze niż podejście typu anonimowego). Z intelektualnej perspektywy zgadzam się, że jest dość nieprzejrzysty.
Dla zainteresowanych kilka podstawowych informacji o jego użyciu w MvcContrib ...
Dodałem to do siatki jako osobistą preferencję - nie lubię używania anonimowych typów jako słowników (posiadanie parametru, który przyjmuje „obiekt” jest tak samo nieprzezroczysty, jak parametr, który przyjmuje parametry Func []), a inicjatorem kolekcji słownika jest raczej gadatliwy (nie jestem też fanem pełnych płynnych interfejsów, np. konieczności łączenia wielu wywołań do atrybutu („styl”, „display: none”). Atrybut („klasa”, „foo”) itp.)
Gdyby C # miał mniej szczegółową składnię literałów słownikowych, nie zawracałbym sobie głowy włączeniem tej składni do komponentu grid :)
Chcę również zauważyć, że użycie tego w MvcContrib jest całkowicie opcjonalne - są to metody rozszerzenia, które owijają przeciążenia, które zamiast tego pobierają IDictionary. Myślę, że ważne jest, aby zapewnić taką metodę, aby wspierać bardziej „normalne” podejście, np. W przypadku współpracy z innymi językami.
Ponadto ktoś wspomniał o „narzutach refleksyjnych”, a ja chciałem tylko zauważyć, że tak naprawdę nie ma narzutów związanych z takim podejściem - nie jest wymagana refleksja środowiska wykonawczego ani kompilacja wyrażeń (patrz http://blog.bittercoder.com /PermaLink,guid,206e64d1-29ae-4362-874b-83f5b103727f.aspx ).
źródło
wolałbym
Jest o wiele bardziej wyraźny i standardowy i nic nie zyskuje dzięki zastosowaniu lambd.
źródło
html.Attributes.Add("style", "width:100%");
nie czyta tak ładnie jakstyle = "width:100%"
(rzeczywisty wygenerowany HTML), alestyle => "width:100%"
jest bardzo podobny do tego, jak to wygląda w wynikowym HTML.Witamy w Rails Land :)
Naprawdę nie ma w tym nic złego, o ile wiesz, co się dzieje. (To wtedy, gdy tego rodzaju rzeczy nie są dobrze udokumentowane, pojawia się problem).
Całość frameworka Railsów opiera się na idei konwencji nad konfiguracją. Nazewnictwo rzeczy w określony sposób wpisuje Cię w konwencję, z której korzystają, a ty dostajesz mnóstwo funkcji za darmo. Przestrzeganie konwencji nazewnictwa prowadzi cię tam, gdzie idziesz szybciej. Wszystko działa świetnie.
Innym miejscem, w którym widziałem taką sztuczkę, są twierdzenia o wywołaniach metod w Moq. Przechodzisz lambda, ale lambda nigdy nie jest wykonywana. Po prostu używają wyrażenia, aby upewnić się, że wywołanie metody się stało, i jeśli nie, zgłaszają wyjątek.
źródło
To jest okropne na więcej niż jednym poziomie. I nie, to nie jest jak Ruby. To nadużycie C # i .Net.
Pojawiło się wiele sugestii, jak to zrobić w prostszy sposób: krotki, anonimowe typy, płynny interfejs i tak dalej.
Co sprawia, że jest tak źle, że jest to po prostu sposób, aby upodobać sobie:
Co się stanie, gdy będziesz musiał zadzwonić z VB?
.Attributes(Function(style) "width:100%")
Jego całkowicie sprzeczna z intuicją inteligencja nie pomoże w ustaleniu, jak przekazać rzeczy.
Jest to niepotrzebnie nieefektywne.
Nikt nie będzie miał pojęcia, jak go utrzymać.
Jakiego rodzaju argumentem są atrybuty?
Func<object,string>
? Jak ujawnia się ta intencja. Jaka będzie twoja dokumentacja intelektualna: „Zignoruj wszystkie wartości obiektu”Myślę, że jesteś całkowicie usprawiedliwiony tym uczuciem odrazy.
źródło
Jestem w obozie „blask składni”, jeśli udokumentują to jasno i wygląda to niesamowicie fajnie, prawie nie ma z tym problemu, imo!
źródło
Oboje Jest to nadużycie wyrażeń lambda ORAZ świetności składni.
źródło
Prawie nigdy nie spotkałem się z takim zastosowaniem. Myślę, że to „nieodpowiednie” :)
Nie jest to powszechny sposób użycia, jest niezgodny z ogólnymi konwencjami. Ten rodzaj składni ma oczywiście wady i zalety:
Cons
Plusy
Podsumowując - w publicznym projekcie API wybrałbym bardziej wyraźny sposób.
źródło
Nie, z pewnością nie jest to powszechna praktyka. Jest to sprzeczne z intuicją, nie ma sposobu, aby po prostu spojrzeć na kod, aby dowiedzieć się, co on robi. Musisz wiedzieć, w jaki sposób jest używany, aby zrozumieć, w jaki sposób jest używany.
Zamiast podawać atrybuty za pomocą tablicy delegatów, metody łączenia byłyby jaśniejsze i działały lepiej:
Chociaż jest to trochę więcej do pisania, jest jasne i intuicyjne.
źródło
.Attribute("style", "width:100%")
daje mistyle="width:100%"
, ale o ile wiem, może mi to daćfoooooo
. Nie widzę różnicy.Czy mogę użyć tego do wykreślenia frazy?
magic lambda (n): funkcja lambda używana wyłącznie w celu zastąpienia magicznego ciągu.
źródło
Co jest nie tak z następującymi:
źródło
Całe to gadanie o „okropnościach” to grupa od dawna przesadnych facetów c # (jestem długoletnim programistą C # i nadal bardzo wielkim fanem języka). W tej składni nie ma nic strasznego. Jest to jedynie próba nadania składni wyglądu bardziej tego, co próbujesz wyrazić. Im mniej „szumu” występuje w składni, tym łatwiej programista może to zrozumieć. Zmniejszenie szumu w jednym wierszu kodu tylko trochę pomaga, ale niech gromadzi się w coraz większej liczbie kodów i okazuje się, że jest to znacząca korzyść.
Jest to próba autora, aby dążyć do tych samych korzyści, które daje DSL - kiedy kod po prostu „wygląda” na to, co próbujesz powiedzieć, osiągnąłeś magiczne miejsce. Możesz debatować, czy jest to dobre dla interop, czy też wystarcza ładniejsze niż anonimowe metody, aby uzasadnić niektóre koszty „złożoności”. W porządku ... więc w swoim projekcie powinieneś dokonać właściwego wyboru, czy użyć tego rodzaju składni. Ale nadal ... jest to sprytna próba programisty zrobienia tego, co na koniec wszyscy próbujemy zrobić (czy zdajemy sobie z tego sprawę, czy nie). A my wszyscy staramy się to zrobić: „Powiedz komputerowi, co chcemy, aby robił w języku, który jest jak najbardziej zbliżony do tego, jak myślimy o tym, co chcemy zrobić”.
Zbliżanie się do wyrażania instrukcji komputerom w taki sam sposób, który naszym zdaniem jest kluczem do uczynienia oprogramowania łatwiejszym w utrzymaniu i dokładniejszym.
EDYCJA: Powiedziałem „klucz do uczynienia oprogramowania łatwiejszym w utrzymaniu i dokładniejszym”, co jest szalenie naiwnym zawyżonym kawałkiem jednorożca. Zmieniłem go na „klucz”.
źródło
Jest to jedna z zalet drzewek wyrażeń - można sprawdzić sam kod w celu uzyskania dodatkowych informacji. W ten sposób
.Where(e => e.Name == "Jamie")
można przekonwertować na równoważną klauzulę SQL Where. To sprytne użycie drzewek wyrażeń, choć mam nadzieję, że nie posunie się ono dalej. Wszystko, co jest bardziej złożone, może być trudniejsze niż kod, który ma zamiar zastąpić, więc podejrzewam, że będzie się samo ograniczać.źródło
To ciekawe podejście. Jeśli prawą stronę wyrażenia ograniczyłeś tylko do stałych, możesz zaimplementować użycie
Myślę, że to, czego naprawdę chcesz zamiast delegata (używasz lambda, aby uzyskać nazwy obu stron) Zobacz naiwną implementację poniżej:
Może to nawet rozwiązać problem wzajemnych interakcji między językami, o którym wspomniano wcześniej w wątku.
źródło
Kod jest bardzo sprytny, ale potencjalnie powoduje więcej problemów, które rozwiązuje.
Jak już zauważyłeś, istnieje teraz niejasna zależność między nazwą parametru (stylem) a atrybutem HTML. Sprawdzanie czasu kompilacji nie jest wykonywane. Jeśli nazwa parametru jest błędnie wpisana, strona prawdopodobnie nie będzie zawierała komunikatu o błędzie środowiska wykonawczego, ale znacznie trudniej będzie znaleźć błąd logiczny (brak błędu, ale nieprawidłowe zachowanie).
Lepszym rozwiązaniem byłoby posiadanie elementu danych, który można sprawdzić w czasie kompilacji. Zamiast tego:
kod z właściwością Style może zostać sprawdzony przez kompilator:
lub nawet:
To więcej pracy dla autorów kodu, ale to podejście wykorzystuje silną funkcję sprawdzania typu C #, która pomaga przede wszystkim zapobiegać dostaniu się błędów do kodu.
źródło
rzeczywiście wygląda na to, że Ruby =), przynajmniej dla mnie użycie statycznego zasobu do późniejszego dynamicznego „wyszukiwania” nie pasuje do rozważań dotyczących interfejsu API, mam nadzieję, że ta sprytna sztuczka jest opcjonalna w tym interfejsie.
Możemy dziedziczyć po IDictionary (lub nie) i zapewnić indeksator, który zachowuje się jak tablica php, gdy nie trzeba dodawać klucza, aby ustawić wartość. Będzie to prawidłowe zastosowanie semantyki .net, nie tylko c #, i nadal będzie wymagała dokumentacji.
mam nadzieję że to pomoże
źródło
Moim zdaniem jest to nadużycie lambdas.
Jeśli chodzi o świetność składni, uważam to za
style=>"width:100%"
mylące. Zwłaszcza z powodu=>
zamiast=
źródło
IMHO, to świetny sposób na zrobienie tego. Wszyscy lubimy fakt, że nazewnictwo kontrolera klasy sprawi, że będzie to kontroler w MVC, prawda? Są więc przypadki, w których nazewnictwo ma znaczenie.
Również intencja jest tutaj bardzo jasna. Bardzo łatwo jest zrozumieć, że
.Attribute( book => "something")
to spowodujebook="something"
i.Attribute( log => "something")
spowodujelog="something"
Myślę, że nie powinno to stanowić problemu, jeśli traktujesz to jak konwencję. Uważam, że cokolwiek sprawia, że piszesz mniej kodu, a intencja jest oczywista, jest dobrą rzeczą.
źródło
Jeśli nazwy metod (func) są dobrze wybrane, jest to świetny sposób na uniknięcie problemów związanych z konserwacją (np. Dodanie nowego func, ale zapomniałem dodać go do listy mapowania parametrów funkcji). Oczywiście musisz to mocno udokumentować i lepiej wygeneruj dokumentację dla parametrów z dokumentacji dla funkcji w tej klasie ...
źródło
Myślę, że nie jest to lepsze niż „magiczne sznurki”. Nie jestem też fanem anonimowych typów. Wymaga lepszego i silnie typowanego podejścia.
źródło