То, что вы делаете, небезопасно, поэтому компилятор жалуется.
Думайте об этом так:
interface IAnimal { }
class Lion : IAnimal { public void Roar() {} }
class Giraffe: IAnimal { }
delegate void D(IAnimal animal);
static void M(Lion lion) { lion.Roar(); }
Теперь вы говорите
D d = M;
Вы понимаете, почему это не работает? Потому что ничто не мешает вам сказать
d(new Giraffe());
и теперь вы только что сделали рев жирафа. Или, скорее, вы просто разбили CLR.
Чтобы предотвратить это, компилятор останавливает попытку выполнить небезопасное назначение.
Обратите внимание, что вы можете пойти другим путем:
delegate void D2(Lion lion);
static void M2(IAnimal animal) {}
...
D2 d2 = M2;
потому что теперь вы собираетесь передать Льва в d2, который передаст IAnimal в M2, и Lion гарантированно реализует IAnimal.
Высокоэффективный способ сказать, что группа методов для делегирования преобразований является контравариантной в своих типах параметров и ковариантной в своих возвращаемых типах.
См. Мою серию статей в блоге о ковариации и контравариантности для получения дополнительной информации.