Code Listings 3
Code Listings 3
Chapter 4 - Advanced C#
Delegates
Delegates
// A delegate type declaration is like an abstract method declaration, prefixed with the delegate keyword.
// To create a delegate instance, assign a method to a delegate variable:
Delegates - longhand
// A delegate variable is assigned a method dynamically. This is useful for writing plug-in methods:
int[] values = { 1, 2, 3 };
Transform (values, Square); // Hook in the Square method
values.Dump();
Transformer t = Test.Square;
Console.WriteLine (t(10)); // 100
class Test
{
public static int Square (int x) => x * x;
}
// When a delegate object is assigned to an instance method, the delegate object must maintain
// a reference not only to the method, but also to the instance to which the method belongs:
class MyReporter
{
public string Prefix = "";
public void ReportProgress (int percentComplete) => Console.WriteLine (Prefix + percentComplete);
}
Multicast Delegates
SomeDelegate d = SomeMethod1;
d += SomeMethod2;
d();
" -- SomeMethod1 and SomeMethod2 both fired\r\n".Dump();
d -= SomeMethod1;
d();
" -- Only SomeMethod2 fired".Dump();
ProgressReporter p = WriteProgressToConsole;
p += WriteProgressToFile;
Util.HardWork (p);
class Util
{
public static void HardWork (ProgressReporter p)
{
for (int i = 0; i < 10; i++)
{
p (i * 10); // Invoke delegate
System.Threading.Thread.Sleep (100); // Simulate hard work
}
}
}
// With this definition, we can write a generalized Transform utility method that works on any type:
public class Util
{
public static void Transform<T> (T[] values, Transformer<T> t)
{
for (int i = 0; i < values.Length; i++)
values[i] = t (values[i]);
}
}
// With the Func and Action family of delegates in the System namespace, you can avoid the
// need for creating most custom delegate types:
int[] values = { 1, 2, 3 };
Util.Transform (values, Square); // Dynamically hook in Square
values.Dump();
// A problem that can be solved with a delegate can also be solved with an interface:
int[] values = { 1, 2, 3 };
Util.TransformAll (values, new Squarer());
values.Dump();
// With interfaces, we’re forced into writing a separate type per transform
// since Test can only implement ITransformer once:
int[] values = { 1, 2, 3 };
Util.TransformAll (values, new Cuber());
values.Dump();
// Delegate types are all incompatible with each other, even if their signatures are the same:
D1 d1 = Method1;
D2 d2 = d1; // Compile-time error
// Delegate types are all incompatible with each other, even if their signatures are the same:
D1 d1 = Method1;
D2 d2 = new D2 (d1); // Legal
void Method1() { }
Delegate Equality
// Delegate instances are considered equal if they have the same method targets:
D d1 = Method1;
// A delegate can have more specific parameter types than its method target. This is called contravariance:
// A delegate can have more specific parameter types than its method target. This is called contravariance:
/* From C# 4.0, type parameters on generic delegates can be marked as covariant (out) or contravariant (in).
Events
Lambda Expressions
Extension Methods
Anonymous Types
Tuples
Records
Patterns
Static Polymorphism
C# 12
in a Nutshell
About the Book
Code Listings
C# 12 in a Nutshell
C# 10 in a Nutshell
C# 9.0 in a Nutshell
C# 8.0 in a Nutshell
C# 7.0 in a Nutshell
Extras
Contact