An enum is a value type that names a set of integer constants (C# specification clause 20). A delegate is a reference type that refers to one or more methods (clause 21).
Enums
enum_declaration:
{attributes} {enum_modifier} enum identifier [ : integral_type ] { [enum_member_list] } [;]
public enum Color
{
Red, // 0
Green, // 1
Blue = 10, // 10
Violet, // 11
Default = Red // 0, a second name for Red
}
public enum Level : byte { Low = 1, High = 2 }
- The underlying type is one of
sbyte,byte,short,ushort,int,uint,longorulong. The default isint. - The first member is 0 unless given a value, and each later member is one more than the one before. Member values are constant expressions and may repeat.
- Enums derive from
System.Enum. They cannot have methods, but extension methods can add them. - A variable of an enum type can hold any value of the underlying type, not just the named members.
Conversions and operators
Conversions to and from the underlying type need a cast. The constant
0 converts implicitly to any enum. Enums support the comparison operators,
+ and - with an integer, subtraction of two values of the same
enum, and the bitwise operators (clause 20.6).
Color c = (Color)1; // Green
int i = (int)Color.Blue; // 10
c == Color.Green; // true
Color none = 0; // the constant 0 converts implicitly
Flags
An enum of bit flags is written with values that are powers of two and the
[Flags] attribute, which changes how ToString formats a
combined value.
[Flags]
public enum Access
{
None = 0,
Read = 1 << 0,
Write = 1 << 1,
Execute = 1 << 2,
ReadWrite = Read | Write
}
Access a = Access.Read | Access.Write;
a.HasFlag(Access.Read); // true
a.ToString(); // "ReadWrite"
Delegates
delegate_declaration:
{attributes} {delegate_modifier} delegate return_type identifier
[variant_type_parameter_list] ( [parameter_list] ) {type_parameter_constraints_clause} ;
public delegate int Transform(int x);
static int Twice(int x) => x * 2;
Transform t = Twice; // method group conversion, C# 2
t(4); // 8, calls t.Invoke(4)
t += x => x + 1; // adds a lambda
int result = t(4); // calls both, returns the last result: 5
- A delegate type derives from
System.MulticastDelegate. Its declaration is the only way to derive from it. - A delegate can refer to static methods, and to instance methods with a target object. A delegate compares equal to one that has the same target and method.
- A delegate is multicast:
+,+=,-and-=add and remove invocations. Delegates are immutable, so each operation creates a new delegate. They run in order, and a non-void delegate returns the last result. - Invoking a null delegate throws
NullReferenceException, sod?.Invoke()is the common form. - A method matches a delegate if the parameter and return types are compatible, and reference types may vary: parameters contravariant, return covariant (clause 21.4).
Func and Action
System defines generic delegates for most uses:
Action<T> takes arguments and returns nothing, and
Func<T, TResult> takes arguments and returns a result. Both exist with
up to 16 arguments. Predicate<T> and
Comparison<T> are older names for common shapes. Generic delegates can
declare variance.
Anonymous methods
An anonymous method (C# 2, clause 12.8.24) creates a delegate from a block. Lambda expressions (C# 3) are now preferred. An anonymous method can leave out its parameter list, so it converts to a delegate with any parameters.
Func<int, int> a = delegate (int x) { return x + 1; };
Action b = delegate { Console.WriteLine("hi"); };
Delegates and events
An event wraps a delegate so that other code can only subscribe. A function pointer (C# 9) is a lower-level alternative in unsafe code.