0% found this document useful (0 votes)
20 views

Code Listings 3

Uploaded by

mbsysde
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
20 views

Code Listings 3

Uploaded by

mbsysde
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 5

11/16/24, 10:57 PM C# in a Nutshell - Code Listings

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:

Transformer t = Square; // Create delegate instance


int result = t(3); // Invoke delegate
Console.WriteLine (result); // 9

int Square (int x) => x * x;

delegate int Transformer (int x); // Our delegate type declaration

Delegates - longhand

Transformer t = new Transformer (Square); // Create delegate instance


int result = t(3); // Invoke delegate
Console.WriteLine (result); // 9

int Square (int x) => x * x;

delegate int Transformer (int x); // Delegate type declaration

Delegates - Writing Plug-in Methods

// 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();

values = new int[] { 1, 2, 3 };


Transform (values, Cube); // Hook in the Cube method
values.Dump();

void Transform (int[] values, Transformer t)


{
for (int i = 0; i < values.Length; i++)
values [i] = t (values [i]);
}

int Square (int x) => x * x;


int Cube (int x) => x * x * x;

delegate int Transformer (int x);

Static method target

Transformer t = Test.Square;
Console.WriteLine (t(10)); // 100

class Test
{
public static int Square (int x) => x * x;
}

delegate int Transformer (int x);

Instance method target

// 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:

MyReporter r = new MyReporter();


r.Prefix = "%Complete: ";
ProgressReporter p = r.ReportProgress;
p(99); // 99
Console.WriteLine (p.Target == r); // True
Console.WriteLine (p.Method); // Void InstanceProgress(Int32)
r.Prefix = "";
p(99); // 99

public delegate void ProgressReporter (int percentComplete);

class MyReporter
{
public string Prefix = "";
public void ReportProgress (int percentComplete) => Console.WriteLine (Prefix + percentComplete);
}

Multicast Delegates

https://w w w .albahari.com/nutshell/E12-CH04.aspx 1/5


11/16/24, 10:57 PM C# in a Nutshell - Code Listings
// All delegate instances have multicast capability:

SomeDelegate d = SomeMethod1;
d += SomeMethod2;

d();
" -- SomeMethod1 and SomeMethod2 both fired\r\n".Dump();

d -= SomeMethod1;
d();
" -- Only SomeMethod2 fired".Dump();

void SomeMethod1 () => "SomeMethod1".Dump();


void SomeMethod2 () => "SomeMethod2".Dump();

delegate void SomeDelegate();

Multicast Delegates - ProgressReporter

ProgressReporter p = WriteProgressToConsole;
p += WriteProgressToFile;
Util.HardWork (p);

void WriteProgressToConsole (int percentComplete)


{
Console.WriteLine (percentComplete);
}

void WriteProgressToFile (int percentComplete)


{
System.IO.File.WriteAllText ("progress.txt", percentComplete.ToString());
}

delegate void ProgressReporter (int percentComplete);

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
}
}
}

Generic Delegate Types

// A delegate type may contain generic type parameters:


int[] values = { 1, 2, 3 };
Util.Transform (values, Square); // Dynamically hook in Square
values.Dump();

int Square (int x) => x * x;

public delegate T Transformer<T> (T arg);

// 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]);
}
}

Func and Action Delegates

// 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();

int Square (int x) => x * x;

public class Util


{
// Define this to accept Func<T,TResult> instead of a custom delegate:
public static void Transform<T> (T[] values, Func<T, T> transformer)
{
for (int i = 0; i < values.Length; i++)
values [i] = transformer (values [i]);
}
}

https://w w w .albahari.com/nutshell/E12-CH04.aspx 2/5


11/16/24, 10:57 PM C# in a Nutshell - Code Listings
Delegates vs Interfaces

// 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();

public interface ITransformer


{
int Transform (int x);
}

public class Util


{
public static void TransformAll (int[] values, ITransformer t)
{
for (int i = 0; i < values.Length; i++)
values[i] = t.Transform (values[i]);
}
}

class Squarer : ITransformer


{
public int Transform (int x) => x * x;
}

Delegates vs Interfaces - Clumsiness

// 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();

public interface ITransformer


{
int Transform (int x);
}

public class Util


{
public static void TransformAll (int[] values, ITransformer t)
{
for (int i = 0; i < values.Length; i++)
values[i] = t.Transform (values[i]);
}
}

class Squarer : ITransformer


{
public int Transform (int x) => x * x;
}

class Cuber : ITransformer


{
public int Transform (int x) => x * x * x;
}

Delegate Type Incompatibility

// Delegate types are all incompatible with each other, even if their signatures are the same:

D1 d1 = Method1;
D2 d2 = d1; // Compile-time error

static void Method1() { }

delegate void D1();


delegate void D2();

Delegate Type Incompatibility - Workaround

// 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 void D1();


delegate void D2();

Delegate Equality

// Delegate instances are considered equal if they have the same method targets:

D d1 = Method1;

https://w w w .albahari.com/nutshell/E12-CH04.aspx 3/5


11/16/24, 10:57 PM C# in a Nutshell - Code Listings
D d2 = Method1;
Console.WriteLine (d1 == d2); // True

static void Method1() { }

delegate void D();

Parameter Compatibility (Contravariance)

// A delegate can have more specific parameter types than its method target. This is called contravariance:

delegate void StringAction (string s);

static void Main()


{
StringAction sa = new StringAction (ActOnObject);
sa ("hello");
}

static void ActOnObject (object o) => Console.WriteLine (o); // hello

Return Type Compatibility (Covariance)

// A delegate can have more specific parameter types than its method target. This is called contravariance:

ObjectRetriever o = new ObjectRetriever (RetriveString);


object result = o();
Console.WriteLine (result); // hello

string RetriveString() => "hello";

delegate object ObjectRetriever();

Type Parameter Variance

/* From C# 4.0, type parameters on generic delegates can be marked as covariant (out) or contravariant (in).

For instance, the System.Func delegate in the Framework is defined as follows:

public delegate TResult Func<out TResult>();

This makes the following legal: */

Func<string> x = () => "Hello, world";


Func<object> y = x;

/* The System.Action delegate is defined as follows:

void Action<in T> (T arg);

This makes the following legal: */

Action<object> x2 = o => Console.WriteLine (o);


Action<string> y2 = x2;

Events

Lambda Expressions

try Statements and Exceptions

Enumeration and Iterators (see also CH7)

Nullable (Value) Types

Nullable Reference Types

Extension Methods

Anonymous Types

Tuples

Records

Patterns

Attributes (see also CH19)

Dynamic Binding (see also CH20)

Operator Overloading (see also CH6)

Static Polymorphism

https://w w w .albahari.com/nutshell/E12-CH04.aspx 4/5


11/16/24, 10:57 PM C# in a Nutshell - Code Listings
Unsafe Code and Pointers (see also CH25)

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

Buy print or Kindle edition

Buy PDF edition

Read via O'Reilly subscription

https://w w w .albahari.com/nutshell/E12-CH04.aspx 5/5

You might also like