Cómo crear un método aceptable adecuadamente

Estoy escribiendo algunos métodos esperados y encontré muchas maneras de hacerlo en Internet. Así que vine aquí para saber lo que realmente está sucediendo en cada sentido, y si hay que desterrar algunos.

Hasta donde yo sé, hay dos tipos de métodos esperados:

Los que llaman a otros métodos esperados:
public async Task<Foo> GetFooAsync()
{
    var foo = await TrulyGetFooAsync();

    // Do stuff with foo

    return foo;
}

No encontré otra forma de hacer esto y creo que es la forma correcta. ¡Dime si estoy equivocado!

Los que solo llaman métodos no esperados:

Y aquí vienen los problemas en mi mente.

Por ejemplo, vi esto:

Ejemplo 1
public async Task<Foo> GetFooAsync()
{
    return await Task.Run(() => TrulyGetFoo());
}

Por lo que yo entiendo, las palabras clave async / wait son inútiles y se pueden evitar para dar esto:

Ejemplo 2
public Task<Foo> GetFooAsync()
{
    return Task.Run(() => TrulyGetFoo());
}

Este último ejemplo es lo que estaba haciendo hasta ahora. Sobre eso, ¿hay alguna diferencia entre:

Task.Run(() => TrulyGetFoo());

y

Task.Run((Foo)TrulyGetFoo); // I don't know if the cast is required at any time but in my code, it was

???

Pero recientemente encontré esta manera:

Ejemplo 3
public Task<Foo> GetFooAsync()
{
    TaskCompletionSource<Foo> tcs = new TaskCompletionSource<Foo>();
    tcs.SetResult(TrulyGetFoo());
    return tcs.Task;
}

Si entendí bien, un método de espera no siempre se ejecuta en otro hilo ??? Supongo que el tercer ejemplo es proporcionar este mecanismo (pero ¿cómo? ¿Solo veo código síncrono en el tercer ejemplo), cuando los ejemplos 1 y 2 siempre se ejecutarán en un subproceso de trabajo?

Es posible que existan otras formas de escribir métodos pendientes, así que avíseme sobre ellos.

Respuestas a la pregunta(3)

Su respuesta a la pregunta