---
name: build-errors-csharp
description: >
  Resolución de errores de compilación C#: dotnet build, MSBuild, NuGet y
  Roslyn. Cubre errores CS comunes, conflictos de versiones NuGet, nullable
  reference types y errores de publicación.
  Cargar cuando un build .NET falle o haya errores de compilación C#.
version: "1.0.0"
herramientasPermitidas: [Read, Bash, Grep]
exclusiones:
  - "No cargar para errores de ASP.NET Core en runtime (middleware, DI, startup) cuando el build compila — si `dotnet build` pasa pero `dotnet run` falla con excepciones de DI, es un error de configuración de la aplicación."
  - "No cargar para fallos de tests MSTest/NUnit/xUnit en assertions aunque el build compile — si el build pasa pero los tests fallan por valores incorrectos, es un error de lógica de tests."
  - "No cargar para diseñar la estructura de solución .NET multi-proyecto desde cero — si la pregunta es cómo organizar proyectos, capas y referencias en una solución, cargar `csharp-patrones` o `csharp-experto`."
  - "No cargar para warnings de analyzer que son informativos y no bloquean el build — solo cargar cuando CS#### o NETSDK#### bloquea la compilación."
evolvable: true  # default para skill estandar
---
# Build Errors C# — Diagnóstico y Solución

## Cuándo NO cargar

- `dotnet build` pasa pero `dotnet run` lanza excepciones de DI o startup — es un error de configuración de la aplicación, no de compilación.
- Los tests xUnit/NUnit fallan en assertions aunque compilan — es un error de lógica de tests.
- La pregunta es cómo organizar solución y proyectos — para diseño de solución cargar `csharp-patrones`.

## Cuándo cargar

- `dotnet build` o `dotnet publish` falla con errores CS o MSBuild
- Conflictos de versión de paquetes NuGet (NU1605, NU1701)
- Errores de nullable reference types (CS8600, CS8602, CS8603)
- Errores de restauración de paquetes en CI
- Problemas de multi-targeting o framework compatibility
- Warnings de Roslyn analyzers que bloquean el build

---

## Errores CS Frecuentes del Compilador Roslyn

### CS0103 — El nombre no existe en el contexto actual

**Causa**: variable, tipo o namespace no importado o mal escrito.

```csharp
// MAL
var lista = new List<string>();
lista.Add("uno");
Console.WriteLine(lista.Count());  // error: Count() no existe sin using System.Linq

// BIEN — agregar el using necesario
using System.Linq;
// ...
Console.WriteLine(lista.Count);   // propiedad, no método, para ICollection
```

### CS0029 — No se puede convertir implícitamente

**Causa**: asignación entre tipos incompatibles sin cast explícito.

```csharp
// MAL
int numero = "42";        // string no convierte a int implicitamente
double precio = 9.99m;   // decimal no convierte a double implicitamente

// BIEN
int numero = int.Parse("42");          // conversión explícita
int numero2 = Convert.ToInt32("42");   // alternativa con manejo de null
double precio = (double)9.99m;         // cast explícito decimal -> double
```

### CS1061 — El tipo no contiene una definición para el miembro

**Causa**: el tipo no tiene esa propiedad o método, o falta un using de extensión.

```csharp
// MAL — falta using para metodos de extension LINQ
List<int> nums = new() { 1, 2, 3 };
var max = nums.Max();  // error CS1061 si falta using System.Linq

// MAL — typo en nombre de propiedad
var persona = new Persona();
Console.WriteLine(persona.Nombr);  // error: debe ser Nombre

// BIEN
using System.Linq;
var max = nums.Max();
```

---

## Nullable Reference Types (C# 8+)

### CS8600 — Asignando null a variable non-nullable

```csharp
// Habilitado en .csproj: <Nullable>enable</Nullable>

// MAL
string nombre = GetNombre();  // error si GetNombre() puede retornar null

// BIEN — opcion 1: declarar como nullable
string? nombre = GetNombre();

// BIEN — opción 2: garantizar no-null con operador de supresión (solo si se está seguro)
string nombre = GetNombre()!;

// BIEN — opción 3: valor por defecto
string nombre = GetNombre() ?? string.Empty;
```

### CS8602 — Dereference posible null

```csharp
// MAL
string? texto = ObtenerTexto();
int longitud = texto.Length;  // error: texto puede ser null

// BIEN — null check antes de acceder
if (texto is not null)
{
    int longitud = texto.Length;
}

// BIEN — operador null-conditional
int? longitud = texto?.Length;
```

### CS8603 — Retorno posible null desde función non-nullable

```csharp
// MAL
public string ObtenerNombre(int id)
{
    return _db.Usuarios.Find(id)?.Nombre;  // error: puede ser null
}

// BIEN
public string? ObtenerNombre(int id)
{
    return _db.Usuarios.Find(id)?.Nombre;
}
```

---

## MSBuild — Errores NETSDK y de Proyecto

### NETSDK1045 — Target framework no soportado

**Causa**: el SDK instalado no soporta el TFM especificado en el proyecto.

```xml
<!-- Diagnóstico: dotnet --list-sdks -->

<!-- MAL — usar net9.0 con SDK 6 instalado -->
<TargetFramework>net9.0</TargetFramework>

<!-- BIEN — usar el TFM soportado por el SDK instalado, o actualizar el SDK -->
<TargetFramework>net8.0</TargetFramework>

<!-- Para multi-targeting -->
<TargetFrameworks>net8.0;net6.0</TargetFrameworks>
```

### NETSDK1138 — Paquete no compatible con target framework

```xml
<!-- Agregar supresión documentada si la compatibilidad es conocida -->
<PackageReference Include="SomeLegacyPackage" Version="1.0.0">
  <NoWarn>NU1701</NoWarn>
</PackageReference>
```

---

## NuGet — Conflictos y Restauración

### NU1605 — Paquete degradado por transitive dependency

**Causa**: dos dependencias requieren versiones incompatibles del mismo paquete.

```xml
<!-- Diagnóstico: dotnet list package --include-transitive -->

<!-- SOLUCIÓN: pinear la versión ganadora explícitamente en el proyecto -->
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />

<!-- Si el conflicto es entre proyectos de la solución, agregar en Directory.Build.props -->
<Project>
  <ItemGroup>
    <PackageReference Update="Newtonsoft.Json" Version="13.0.3" />
  </ItemGroup>
</Project>
```

### Fallo de restauración en CI — paquetes no encontrados

```bash
# Causas comunes y diagnostico
dotnet restore --verbosity detailed 2>&1 | grep -i "error\|not found"

# Si el feed privado falla: verificar NuGet.Config con credenciales
# Nunca commitear credenciales en NuGet.Config — usar variables de entorno
dotnet restore --configfile ./NuGet.Config

# Forzar restauracion limpia
rm -rf ~/.nuget/packages  # Linux/Mac
dotnet nuget locals all --clear
dotnet restore
```

---

## Roslyn Analyzers — Warnings como Errores

### Configuración correcta de TreatWarningsAsErrors

```xml
<!-- MAL: silenciar todos los warnings en lugar de resolver -->
<NoWarn>CS8600;CS8602;CS8603</NoWarn>

<!-- BIEN: resolver los warnings o suprimirlos con justificación -->
<!-- En el código, con razón documentada -->
#pragma warning disable CS8602 // El null check ocurre en el middleware anterior
var resultado = _servicio.Procesar();
#pragma warning restore CS8602

<!-- BIEN en .editorconfig para reglas de estilo (no de correctitud) -->
dotnet_diagnostic.IDE0028.severity = suggestion  # coleccion init simplificable
```

---

## Errores de Publicación

### Error al publicar self-contained (RID no encontrado)

```bash
# MAL — publicar sin especificar RID para self-contained
dotnet publish -c Release --self-contained

# BIEN — especificar el RID objetivo
dotnet publish -c Release -r linux-x64 --self-contained true
dotnet publish -c Release -r win-x64 --self-contained false  # framework-dependent

# RIDs comunes: win-x64, win-x86, linux-x64, linux-arm64, osx-x64, osx-arm64
```

---

## Gotchas / Errores comunes no obvios

- **`<Nullable>enable</Nullable>` activado en el proyecto produce 300+ warnings que bloquean CI con TreatWarningsAsErrors**: la migración a nullable contexts no es atómica — activar `enable` en un codebase sin anotaciones existentes genera warnings masivos que se convierten en errores. Causa: C# 8+ nullable analysis requiere que todas las referencias que pueden ser null sean explícitamente anotadas como `T?`. Solución: activar `enable` progresivamente usando `#nullable enable` solo en archivos nuevos o migrados, y `#nullable disable` en archivos legados — no activar en todo el proyecto de golpe.
- **Conflicto NuGet NU1605 resuelto con `BindingRedirect` que no tiene efecto en .NET Core/5+**: las redirecciones de binding son una característica de .NET Framework; en .NET Core y superiores no aplican. Causa: el desarrollador copió la solución de StackOverflow para .NET Framework y la aplicó a un proyecto .NET 6. Solución: en .NET Core+, usar `<PackageReference Include="X" Version="Y" />` directo con la versión unificada en `Directory.Build.props`, o agregar `<VersionOverride>` en el proyecto hijo.
- **`dotnet restore` falla en CI con "Unable to load the service index for source"** pero funciona localmente: la URL del NuGet feed privado o el token de autenticación no están configurados en el entorno CI. Causa: localmente hay una credencial almacenada en `~/.nuget/NuGet/NuGet.Config` que no existe en el agente CI. Solución: configurar el feed en `nuget.config` del proyecto con la URL y usar `NUGET_PACKAGES` + credenciales como variables de entorno del CI — no almacenar credenciales en el archivo de config.
- **Roslyn analyzer genera error CA1416 (platform compatibility) para código que solo corre en Windows pero el target framework es `net8.0`**: sin `[SupportedOSPlatform("windows")]` en el método o clase que llama a la API, el analyzer reporta el error aunque el código esté en un `#if WINDOWS` block. Causa: el analyzer analiza el código sin evaluar las directivas de pre-procesador. Solución: anotar el método con `[SupportedOSPlatform("windows")]` o usar target framework específico de plataforma `net8.0-windows` para el proyecto que contiene ese código.

## Checklist de Diagnóstico

- [ ] Leer el código de error completo (CS#### o NETSDK####) antes de buscar solución.
- [ ] `dotnet build --verbosity diagnostic` para log completo de MSBuild.
- [ ] `dotnet list package --outdated` para identificar paquetes desactualizados.
- [ ] `dotnet list package --include-transitive` para ver árbol de dependencias.
- [ ] Verificar que `<Nullable>enable</Nullable>` es intencional y el código lo maneja.
- [ ] En CI: asegurar que la versión del SDK coincide con `global.json` del proyecto.
- [ ] Para conflictos NuGet: usar `Directory.Build.props` en la raíz de la solución.
- [ ] `dotnet nuget locals all --clear` si la caché local está corrompida.
