Первые два подхода фактически идут рука об руку. Метод BeginInvoke возвращает IAsyncResult, который вы позже используете для вызова EndInvoke позже. Третий метод скрывает большую часть этой сложности, позволяя дать ему делегат для вызова, когда он завершит свою задачу (обычно немного проще в использовании).