```cs
public delegate void DrawDelegate1();
public delegate void DrawDelegate2(int size);

public class Pen
{
    public int Size { get; set; }

    public void Draw(DrawDelegate1 how1, DrawDelegate2 how2)
    {
        how1();
        how2(Size);
    }
}
```
  
```cs
// public delegate void LogDelegate(string text, params string[] args);

public class L {
	public delegate void LogDelegate(string text, params string[] args);
	private void Log(LogDelegate logDelegate, string text, params string[] args) {
		logDelegate(text, args);
		log(Console.WriteLine, text, args);
	}
	
	public void LogConsole(string text, params string[] args) {
		Console.WriteLine(text, args);
	}
	
	public void LogDebug(string text, params string[] args) {
		Log(Debug.WriteLine, text, args);
	}
	public void LogToM(string text, params string[] args) {
		Log(M.Log, text, args);
	}
}

public class M {
	public static void Log(string message, params string[] args) {
		Console.WriteLine(message, args);
	}
	
	private LogDelegate _logDelegate;
}

static void Lesson4() {
	var l = new L();
	var m = new M();
	l.Log(Console.WriteLine, "{0}, {1}!", "Hello", "World");
	l.Log(M.Log, "{0}, {1}!", "Hello", "World");
}
```
## Action, Func, Predicate
```cs
public class Pen
{
    public int Size { get; set; }

    public void Draw(Action how1, Action<int> how2)
    {
        how1();
        how2(Size); 
    }

    public void Foo(Predicate<int> p, Func<int> f1, Func<int, int> f2)
    {
        bool b = p(Size);
        int s1 = f1();
        int s2 = f2(Size);
    }
}
```
#### Подписка и отписка
```cs
public class Pen
{
    public int Size { get; set; }

    public void Draw(Action how1, Action<int> how2)
    {
        how1();
        how2(Size); 
    }

    public void Foo()
    {
        Action<Action, Action<int>> how = Draw;
        how += Draw;
        how -= Draw;
    }
}
```

```cs
public class L {
	public delegate void LogDelegate(string text, params string[] args);
	
	public void Log(LogDelegate logDelegate, string text, params string[] args) {
		logDelegate(text, args);
	}
	
	public void Log2(Action<string> logAction, ) {
		logAction(text, args);
	}
	
	private LogDelegate _logDelegate;
	
	private void Register(LogDelegate logDelegate) {
		_logDelegate += logDelegate;
	}
	
	private void UnRegister(LogDelegate logDelegate) {
		_logDelegate -= logDelegate;
	}
	
	private void UnRegister() {
		foreach (var action in _logDelegate.GetInvocationList()) {
			_logDelegate -= (LogDelegate)action;
		}
	}
	
	public void Log3(string text, params string[] args) {
		_logDelegate?.Invoke(text, args);
	}
}

static void Lesson4() {
	var l = new L();
	var m = new M();
	l.Log(Console.WriteLine, "{0}, {1}!", "Hello", "World");
	l.Log(M.Log, "{0}, {1}!", "Hello", "World 1");
	l.Log2(Debug.WriteLine, "Hello World 2");
	void Test(string text, params string[] args) {
		Console.WriteLine(text, args);
	}
	l.Register(Console.WriteLine);
	l.Register(M.Log);
	l.Register((message, args) => Console.WriteLine(message, args));
	l.Register(Test);
	l.UnRegister(Console.WriteLine);
	l.UnRegister(M.Log);
	//l.UnRegister((message, args) => Console.WriteLine(message, args));
	l.Log3("{0} {1}!", "Hello", "World 3");
	l.Register(Test);
}
```
## События
```cs
public class Pen
{
    public int Size { get; set; }

    private Action<int> _drawDone;

    public event Action<int> OnDrawDone
    {
        add => _drawDone += value;
        remove => _drawDone -= value;
    } 
    public void Draw()
    {
        Size--;
        _drawDone(Size);
    }
}
```

```cs
public class Pen
{
    public int Size { get; set; }

    public event Action<int> OnDrawDone;

    public void Draw()
    {
        Size--;
        OnDrawDone(Size);
    }
}
```

```cs
public class Pen
{
    public int Size { get; set; }

    public event Action<int> OnDrawDone;

    public void Draw()
    {
        Size--;
        OnDrawDone?.Invoke(Size);
    }
}
```

```cs
public class M {
	public static void Log(string message, params string[] args) {
		Console.WriteLine(message, args);
	}
	
	private LogDelegate _logDelegate;
	
	/*
	public event LogDelegate LogDelegate {
		add {
			_logDelegate += value;
		}
		remove {
			_logDelegate += value;
		}
	}
	*/
	
	public event LogDelegate LogDelegate;
	public event EventHandler<SomeEventArgs> LogDelegate2;
	
	public void Log4(string text, params string[] args) {
		LogDelegate?.Invoke(this, new SomeEventArgs(text, args));
		Log5(text, args);
	}
}

public class SomeEventArgs(string Text, string[] Args) : EventArgs {
	public string Text { get; } = text;
	public string[] Args { get; } = args;
}

static void Lesson4() {
	var m = new M();
	m.LogDelegate += Console.WriteLine;
	m.LogDelegate += M.Log;
	m.LogDelegate += M.Log;
	m.LogDelegate -= M.Log;
	m.LogDelegate -= M.Log;
	m.Log4("{0} {1}!", "Hello", "World 4");
	
	m.LogDelegate2 += (s, e) => Console.WriteLine(e.Text, e.Args);
	m.Log5("{0} {1}!", "Hello", "World 5");
}
```
## Лямбды
```cs
public class Paper
{
    public void Draw(Pen pen)   
    {
        pen.OnDrawDone += PenOnOnDrawDone; 
        pen.Draw();
    }

    private void PenOnOnDrawDone(int size)
    {
        Console.WriteLine("Draw {size}", size);
    }
}

// Ламбда-выражения

(список_параметров) => выражение;
```

```cs
public class Paper
{
    public void Draw(Pen pen)
    {
        pen.OnDrawDone += (size) =>
        {
            Console.WriteLine("Draw {size}", size);
        };
        pen.Draw();
    }
}
```