Cómo aprobar una entrevista de C#: principales preguntas de nivel avanzado
La entrevista para el puesto de desarrollador Senior C# no solo es una prueba de sintaxis, sino también una comprensión profunda del funcionamiento interno de .NET, la optimización del rendimiento y las decisiones arquitectónicas. En este artículo, analizaremos los temas clave que suelen surgir en las entrevistas técnicas. Aprenderás cómo responder preguntas complejas y obtendrás ejemplos de código listos para demostrar tus habilidades.
1. Programación asíncrona: async/await y Task
Las preguntas sobre async y await son clásicas en cualquier entrevista avanzada. Los entrevistadores quieren ver que entiendes cómo funciona el contexto de sincronización y cómo evitar deadlocks.
Pregunta típica: "¿Qué sucede si se llama a .Result o .Wait() en un método asíncrono dentro del hilo de la UI?"
Respuesta: Se producirá un deadlock, ya que el hilo principal se bloqueará esperando el resultado, mientras que la continuación del método asíncrono intentará regresar al mismo contexto de sincronización, que está ocupado. La solución es usar ConfigureAwait(false) o hacer la llamada completamente asíncrona.
public async Task<string> GetDataAsync(){ // Trabajo correcto con el contexto var result = await SomeHttpCallAsync().ConfigureAwait(false); return result;}
// Error: deadlock en UI/ASP.NET Core (hasta .NET Core 2.1)// var data = GetDataAsync().Result;Pregunta adicional: "¿Cuál es la diferencia entre Task.Run y Task.Factory.StartNew?"
Task.Run usa el grupo de subprocesos predeterminado y automáticamente desenvuelve tareas anidadas. StartNew ofrece más control (por ejemplo, se puede especificar TaskCreationOptions.LongRunning), pero requiere la gestión manual de Unwrap() para delegados asíncronos.
2. LINQ y ejecución diferida (Deferred Execution)
LINQ es una herramienta poderosa, pero su uso incorrecto puede provocar una caída en el rendimiento. Las preguntas avanzadas suelen tratar sobre IQueryable vs IEnumerable y la materialización de consultas.
Pregunta: "¿Por qué el siguiente código realiza varias consultas a la base de datos?"
var query = context.Products.Where(p => p.Price > 100);foreach (var product in query){ Console.WriteLine(product.Name);}var count = query.Count(); // ¡Segunda consulta!Respuesta: IQueryable representa una expresión (Expression Tree) que se traduce a SQL. Cada vez que se itera o se llama a una función de agregación (Count, Sum), el SQL se envía nuevamente. Para evitarlo, es necesario materializar los datos: var list = query.ToList();
Matiz avanzado: La diferencia entre First() y FirstOrDefault() — First() lanza una excepción si la secuencia está vacía, lo que puede ser más costoso en términos de manejo de errores.
3. Gestión de memoria y Garbage Collector (GC)
Comprender el funcionamiento del GC es una señal de un desarrollador Senior. Las preguntas pueden tratar sobre generaciones (Generations), finalización y el patrón Dispose.
Pregunta: "¿Qué es el Large Object Heap (LOH) y por qué hay que tener cuidado con él?"
Respuesta: LOH es el montón para objetos de más de 85 000 bytes. A diferencia del Small Object Heap, LOH no se compacta (hasta .NET 4.5.1), lo que provoca fragmentación de la memoria. Esto puede causar OutOfMemoryException, incluso si hay mucha memoria libre. Recomendaciones: usar grupos de objetos o dividir arrays grandes en partes.
// Ejemplo de mala prácticabyte[] largeBuffer = new byte[100_000]; // Cae en LOH
// Mejor: usar ArrayPoolbyte[]