Vor Kurzem hatte ich bereits über den Sinn von Extension Methods geschrieben und bin jetzt auf ein weiteres sehr gutes Beispiel für deren Verwendung gestoßen: Die Erweiterung einer Enumeration um Bitmasken auf gesetzte Werte zu prüfen.
Dank des Attributes „Flags“ wird aus einer einfachen Enumeration eine Bitmaske, siehe Beispiel:
[Flags] public enum AccessRights { None=0, Read, Write, Execute }
Die Erweiterungsmethoden prüfen per Bitvergleich ob alle übergebenen Flags im aktuellen Objekt gesetzt sind. Dies geht über eine einfache UND Verknüpfung welche alle Bits nullt die nicht in beiden Werten gesetzt sind. Entspricht das Endergebnis den hineingegebenen Flags, sind sie alle gesetzt. Ist es jedoch 0 hat keines überlebt sprich die angegeben Flags waren nicht gesetzt.
public static class AccessRightsExtensions { public static bool IsSet(this AccessRights value, AccessRights flags) { return (value & flags) == flags; } public static bool IsNotSet(this AccessRights value, AccessRights flags) { return (value & flags) == 0; } }
Oder um es noch einmal in Bitschreibweise zu machen
IsSet: value = 011101 flags = 011000 & 011000 == flags -> true IsNotSet: value = 011101 flags = 100010 & 000000 == 0 -> true
Zum Abschluss gibt es jetzt noch ein kleines Beispiel wie diese Methoden eingesetzt werden könnten:
public class UserFile { private AccessRights Rights; public bool IsVisibleToUser { get { return Rights.IsSet(AccessRights.Read); } } public Stream OpenReadWrite() { if(Rights.IsNotSet(AccessRights.Read | AccessRights.Write)) { throw new Exception("Insufficient privileges"); } ... }
Verwirrend mag auf den ersten Blick die Oder-Verkettung innerhalb von OpenReadWrite sein. Denn im Grunde möchte man ja prüfen ob beide Rechte gesetzt sind. Da es sich aber um eine bitweise Verkettung handelt entspricht das Oder an dieser Stelle einem Und.