Artykuł

freeimages.com freeimages.com
kwi 29 2015
0

Enum jako flaga

Enum jest bardzo pożyteczną konstrukcją, której używam praktycznie w każdym, nawet najmniejszym projekcie. Enumeracja ma praktycznie same zalety - przede wszystkim pozwala na definiowanie stałych wartości, które później można łatwo użyć w dowolnym miejscu w naszym kodzie. Jak na razie wszystko jest jasne i oczywiste. Mniej znaną właściwością enumów jest praca w trybie flagi, dzięki czemu enumeracja dostaje dodatkowego kopa;-) Przykład umieszczony w dalszej części tekstu pokaże jakie może to przynieść korzyści.

Teoria

Aby enum działał w trybie flagi, muszą być spełnione dwa warunki. Przede wszystkim musimy umieścić atrybut Flags przed samą enumeracją. Po drugie, musimy nadać odpowiednie wartości wszystkim elementom naszego enuma. Na dodatek, nie mogą to być byle jakie wartości, ponieważ mamy w tym przypadku do czynienia z tzw. przesunięciem bitowym i każda kolejna wartość musi się wpisywać w poniższy wzorzec:

0000  0
0001  1
0010  2
0100  4
1000  8
itd.

W każdej kolejnej wartości mamy przesunięcie bitowe w lewo.

Wartości flag możemy zapisywać na różne sposoby, ot choćby tak:

// 1
[Flags]
enum CarType
{
	None = 0
	Sedan = 1,
	Hatchback = 2,
	Combi = 4
}

// 2
[Flags]
enum CarType
{
	None = 0x0
	Sedan = 0x1,
	Hatchback = 0x2,
	Combi = 0x4
}

Największą jednak ich zaletą jest możliwość stosowania operatorów:

  • OR - do tworzenia kombinacji określonych typów:
    var allCars = CarType.Sedan | CarType.Hatchback | CarType.Combi;
  • XOR - do tworzenia wykluczających się alternatyw:
    var sedanOrHatchback = allCars ^ CarType.Combi;

Poniżej krótki przykład praktyczny.

Przykład - repozytorium

Przykład który chciałem Wam zaprezentować jest stosunkowo prosty. Utworzymy pewne repozytorium obiektów typu Car, z którego będziemy mogli wyciągać samochody określonego typu. Żeby było ciekawiej, skorzystamy tutaj z flag, co w połączeniu z operatorem OR pozwoli na pobieranie samochodów kilku typów naraz;-)

Najpierw zaczniemy od enumeracji:

[Flags]
enum CarType
{
	Sedan = 1,
	Hatchback = 2,
	Combi = 4
}

W kolejnym kroku zdefiniujemy również klasę Car, która posiadać będzie dwie proste właściwości - w tym naszego nowego enuma:

class Car
{
	public CarType CarType { get; set; }
	public string Name { get; set; }
}

Centralnym elementem przykładu będzie klasa CarManager. W jej wnętrzu znajdziemy proste repozytorium, a także metodę do wyciągania samochodów według typu.

class CarManager
{
	private readonly ICollection<Car> cars = new List<Car>
	{
		new Car { CarType = CarType.Sedan, Name = "Sedan 1"},
		new Car { CarType = CarType.Sedan, Name = "Sedan 2"},
		new Car { CarType = CarType.Sedan, Name = "Sedan 3"},
		new Car { CarType = CarType.Hatchback, Name = "Hatchback 1"},
		new Car { CarType = CarType.Hatchback, Name = "Hatchback 2"},
		new Car { CarType = CarType.Combi, Name = "Combi 1"},
		new Car { CarType = CarType.Combi, Name = "Combi 2"},
	};

	public IEnumerable<Car> GetCars(CarType carType)
	{
		return cars.Where(c => carType.HasFlag(c.CarType));
	}
}

Sercem tej metody jest zapytanie LINQ w którym szukamy wszystkich samochodów, które zawierają się w zestawie flag przekazanych w parametrze metody.

Zwieńczeniem przykładu jest klasa Program, w której testujemy różne wywołania metody GetCars za pomocą operatora bitowego OR (OR czyli lub):

class Program
{
	static void Main(string[] args)
	{
		CarManager manager = new CarManager();
		PrintOutCars(manager.GetCars(CarType.Sedan));
		PrintOutCars(manager.GetCars(CarType.Sedan | CarType.Hatchback));
		PrintOutCars(manager.GetCars(CarType.Sedan | CarType.Hatchback | CarType.Combi));
		Console.ReadKey();
	}

	private static void PrintOutCars(IEnumerable<Car> cars)
	{
		Console.WriteLine("Liczba zwróconych samochdów: {0}", cars.Count());
		foreach(var car in cars)
		{
			Console.WriteLine("Typ samochodu: {0}, nazwa: {1}", car.CarType, car.Name);
		}

	}
}

Jak widać flagi mogą być bardzo użyteczne - o ile tylko mamy na nie jakiś sensowny pomysł. Warto również wspomnieć, że można z nich korzystać również w metodach WebApi.

Data ostatniej modyfikacji: 04.05.2015, 21:47.

Podoba Ci się ten wpis? Powiedz o tym innym!

Send to Kindle

Komentarze

blog comments powered by Disqus