fbpx
devstyle.pl - Blog dla każdego programisty
devstyle.pl - Blog dla każdego programisty
< 1 minut

String.ToEnum<>


03.02.2010

Mając wartość enuma w postaci napisowej, pobraną na ten przykład z bazy, bardzo łatwo jest z powrotem sparsować ją do właściwego dla aplikacji typu:

  1:  public enum MyEnum
  2:  {
  3:  	FirstVal,
  4:  	SecondVal
  5:  }
  6:  //...
  7:  (MyEnum)Enum.Parse(typeof(MyEnum), "FirstVal");

Powtarzanie tego w kodzie jest jednak dość męczące. I po raz kolejny świetny mechanizm Extension methods przychodzi na ratunek:

  1:  public static class StringExtensions
  2:  {
  3:  	public static TEnum ToEnum<TEnum>(this string _this) where TEnum : struct
  4:  	{
  5:  		return (TEnum)Enum.Parse(typeof(TEnum), _this, true);
  6:  	}

Zwracam uwagę na warunek nałożony na parametr generyczny (where TEnum : struct). Wszystkie typy wyliczeniowe dziedziczą z value-types, dzięki temu już na etapie kompilacji otrzymujemy pewną (choć nie 100%-ową) weryfikację przekazywanego typu – ponieważ "jeśli jest to typ referencyjny to nie jest enumem".

A efekt końcowy o ile ładniejszy od poprzedniego:

  1:  "FirstVal".ToEnum<MyEnum>()
Notify of
Szymon Pobiega

Faaajne:) Uwielbiam takie małe i funkcjonalne kawałki kodu. Jest tylko jeden problem — gdzie taki kod umieszczać? Kopiowanie go i wklejanie do każdego projektu mi się zbytnio nie podoba. Z drugiej strony tworzenie dll-ki z jedną lub kilkoma metodami też jest takie średnie. Z trzeciej zaś — jedna wielka dll-ka, w której są wszystkie przyjemne "snippety" to też jakoś nie to. Masz w tej kwestii jakieś sprawdzone rozwiązanie?

procent

@Szymon Pobiega:
U mnie "sprawdzonym rozwiązaniem" jest jednak kopiowanie z projektu do projektu:). Ale nie mam zbioru stałych "starterów" które dodaję już na początku. Po prostu w razie potrzeby sięgam do już stworzonych rozwiązań i umieszczam je w aktualnym projekcie. I sobie ewoluują… Z jednej strony nie jest to idealne, ale z drugiej strony – takie pomocnicze rzeczy są zwykle banalnie proste, więc w takiej powtarzalności nie widzę problemu. Na pewno wolę to niż jakąś "Procent.Common.dll":) która będzie wielkim śmietnikiem dodawanym do referencji każdego mojego projektu jako pierwsza i konieczna zależność.

emdzej

Mały i elegancki helper ;) Bardzo lubie takie "zgrabne" rozwiązania!

Assassin
Assassin

@Procent
A czemu nie widzisz jednej duzej dll’ki? Rozumime zmienne dla aktualnego projektu ( bo sa jakos unikatowe) ale takie rzeczy jak dostep do danych (jesli masz) albo inne uzyteczne snippety/biblioteki ktore sie nie zmieniaja to czemu nie?

Pytam bo moze sa tam jakies za i przeciw ktory nie widze, bo zawsze ide Common.dll byla dla mnie akceptowala i uwazalem ja za dobra

Pozdrawiam.

procent

Miałem w firmach kilkukrotnie styczność z takimi "common.dll". A to <firma>.Common.DataAccess.dll, a to <firma>.Common.Utils.dll, a to jeszcze inne wynalazki. Są trzy drogi: 1) każdy aktualnie realizowany (i przeszły) projekt ma własną niezależnie rozwijaną kopię -> co od kopiowania jedynie wybranych, potrzebnych w konkretnym przypadku mechanizmów różni się tylko tym że ciągniemy ze sobą masę zbędnych rzeczy; 2) mamy jedną, nieustannie (siłą rzeczy) rozwijaną "instancję" biblioteki i każdy projekt ma do niej referencje (przez externals w svn czy submodules w gicie); ograniczając się jedynie do "przyrostowego" rozwijania biblioteki tego typu może być średnio wygodne, ponieważ w takich kawałkach kodu często mogą… Read more »

Dawid Kowalski

Piszesz "Mając wartość enuma w postaci napisowej, pobraną na ten przykład z bazy" – jak się zapatrujecie na przetrzymywanie stringów zamiast wartości całkowitych w bazie ? Z jednej strony fajnie bo w bazie mamy czarno na białym konkretną wartość, z drugiej napis może się zmienić a wartość pozostanie wartością. I jeszcze kilka innych argumentów za jedną czy drugą stroną się znajdzie. To jak to jest u was i dlaczego ?

dario-g

Jako, że nieraz borykałem się z: a) problemem dużego przyrostu wielkości bazy b) wydajnością – to jestem za używaniem liczb. Szczególnie, że często taki enum nie wykracza poza wielkość byte, a co za tym idzie tinyint w MSSQLu.

Czytelność bazy? Skoro baza to tylko zbiornik danych, a mięsko to kod programu to kto zagląda rękami do bazy? OK, raporty… trzeba czasami napisać skomplikowaną procedurę/zapytanie rękami, ale nie ma ich tak wiele, aby sobie z tym nie poradzić. Poza tym bardziej skomplikowany raport wymaga wcześniejszego przygotowania podłoża (czyli m.in. wyciągnięcie z kodu/dokumentacji (z naciskiem na dokumentację) znaczenia dla wartości enuma.

procent

@Dawid Kowalski: Moim zdaniem nie ma "złotej reguły". Jeśli taki enum miałby być mapowany na najprostszą tabelę słownikową (id+nazwa) z kilkoma zaledwie elementami (np. stan zamówienia) to nie ma sensu tworzyć osobnej tabeli. Nie chodzi nawet o to że w bazie wszystko jest "czarno na białym" – po prostu tak jest prościej. Jeśli natomiast miałyby się tam znajdować dodatkowe informacje edytowalne/konfigurowalne z poziomu UI (jak Name/DisplayName/Description czy np. nazwa typu który jest odpowiedzialny za obróbkę zamówienia w danym stanie) to osobna tabela jest wręcz niezbędna. Tak więc – nie widzę nic złego w trzymaniu napisów bezpośrednio w tabeli, ale gdy… Read more »

PiotrB

2) mamy jedną, nieustannie (siłą rzeczy) rozwijaną "instancję" biblioteki i każdy projekt ma do niej referencje (przez externals w svn czy submodules w gicie); ograniczając się jedynie do "przyrostowego" rozwijania biblioteki tego typu może być średnio wygodne, ponieważ w takich kawałkach kodu często mogą nastąpić zmiany (ciągle da się wymyślać lepsze sposoby na rozwiązanie częstych problemów); natomiast modyfikacja już napisanego kodu może zadziałać w jednym projekcie, ale popsuć wszystkie inne… w ten sposób nawet nasze wewnętrzne API musimy traktować jako de facto udostępniony na zewnątrz framework, a taki krok chyba najlepiej odsunąć w czasie tak daleko jak to możliwe Właśnie… Read more »

Jacek Ciereszko

To ja się podzielę implementacją ToEnum którą ja akurat wykorzystuje: [DebuggerStepThrough] public static T ToEnum<T>(this string target, T defaultValue) where T : IComparable, IFormattable { T convertedValue = defaultValue; if (!string.IsNullOrEmpty(target)) { try { convertedValue = (T) Enum.Parse(typeof(T), target.Trim(), true); } catch (ArgumentException) { // jakas tam obsluga } } return convertedValue; } To co lepsze? "where T : IComparable, IFormattable" czy "where TEnum : struct"

Gutek

@Jacek lepsze jest struct, ze wzgledu na to ze Enum nie moze byc klasa – jest typu value type i w systemie traktowany jest jako struktura (sa tylko dwie kategorie strutkrualne, enum i struct). Twoje rozwiaznie zezwala na przekazywanei obiektow – nie zaleznie jakie bys dodal tam interfejsy. Przyklad: public class Test : IComparable, IFormattable { public int CompareTo(object obj) { return 0; } public string ToString(string format, IFormatProvider formatProvider) { return base.ToString(); } } u Ciebie wywali to blad, u Procenta bedzie blad kompilacji – imo, lepsze rozwiazanie. Jedynym przypadkiem kiedy u Procenta moze pojawic sie blad to wtedy… Read more »

Artur
Artur

@Procent "Moim zdaniem nie ma "złotej reguły". Jeśli taki enum miałby być mapowany na najprostszą tabelę słownikową (id+nazwa) z kilkoma zaledwie elementami (np. stan zamówienia) to nie ma sensu tworzyć osobnej tabeli." Możesz mieć jedną tabelę słownik i trzymać w niej takie rzeczy. Możesz przy zapisie do bazy rzutować na byte, przy odczycie na MyEnum. Pewnie można wymyśleć jeszcze wiele innych rozwiązań. W Twoim przypadku zmiana nazwy elementu enuma już zaczyna być problemem. A nigdy tak nie zrobiłem z powodów opisanych przez Dario-G. Co do bibliotek, to przez większą część zawodowej kariery spotykałem się z (1) rozwiązaniem. Obecnie pracuję z… Read more »

Kurs Gita

Zaawansowany frontend

Szkolenie z Testów

Szkolenie z baz danych

Facebook

Książka

Zobacz również