Skip to content

Fix: C# Cannot implicitly convert type 'X' to 'Y'

FixDevs ·

Quick Answer

How to fix C# cannot implicitly convert type error caused by type mismatches, nullable types, async return values, LINQ result types, and generic constraints.

The Error

You compile C# code and get:

error CS0029: Cannot implicitly convert type 'string' to 'int'

Or variations:

error CS0029: Cannot implicitly convert type 'int?' to 'int'
error CS0029: Cannot implicitly convert type 'System.Collections.Generic.List<int>' to 'System.Collections.Generic.IEnumerable<string>'
error CS0266: Cannot implicitly convert type 'double' to 'float'. An explicit conversion exists (are you missing a cast?)
error CS0029: Cannot implicitly convert type 'Task<string>' to 'string'

You assigned or returned a value of one type where a different type is expected. C# does not allow implicit conversions between incompatible types, or between types where the conversion could lose data.

Why This Happens

C# is a statically typed language. Every variable, parameter, and return value has a declared type. When you assign a value of one type to a variable of another type, the compiler checks if an implicit conversion exists.

Implicit conversions are allowed when no data loss is possible:

int x = 42;
long y = x;     // OK — int fits in long
double z = x;   // OK — int fits in double

Implicit conversions are NOT allowed when data could be lost or types are incompatible:

double d = 3.14;
int i = d;          // Error — would lose decimal part
string s = 42;      // Error — int is not a string
int? n = 5;
int x = n;          // Error — nullable might be null

Common causes:

  • Wrong variable type. Assigning a string to an int, or vice versa.
  • Nullable type mismatch. Assigning int? to int without handling the null case.
  • Missing await. Using the result of an async method without await, getting Task<T> instead of T.
  • LINQ type mismatch. A LINQ query returns a different type than expected.
  • Narrowing numeric conversion. Assigning a double to a float, or a long to an int.
  • Generic type mismatch. Passing List<Derived> where List<Base> is expected.

Fix 1: Use Explicit Casting

When the compiler says an explicit conversion exists, add a cast:

double d = 3.14;
int i = (int)d;          // Explicit cast — truncates to 3

long bigNumber = 100L;
int smallNumber = (int)bigNumber;  // Explicit cast — OK if value fits

float f = (float)d;      // double → float — may lose precision

Be careful with overflow:

long huge = long.MaxValue;
int overflow = (int)huge;  // Silent overflow — result is -1!

// Safer — throws OverflowException if value doesn't fit:
int safe = checked((int)huge);

Pro Tip: Use checked blocks when casting between numeric types if the value might not fit. Without checked, C# silently overflows, which can cause hard-to-find bugs. In production code, enable project-wide overflow checking with <CheckForOverflowUnderflow>true</CheckForOverflowUnderflow> in your .csproj.

Fix 2: Use Conversion Methods for String ↔ Number

You cannot cast between strings and numbers. Use conversion methods:

String to number:

string input = "42";

// Parse — throws if invalid
int number = int.Parse(input);
double d = double.Parse(input);

// TryParse — returns false if invalid (preferred)
if (int.TryParse(input, out int result))
{
    Console.WriteLine(result);
}

// Convert class
int n = Convert.ToInt32(input);

Number to string:

int number = 42;
string s = number.ToString();
string formatted = number.ToString("N2");  // "42.00"
string interpolated = $"{number}";         // String interpolation

Common mistake — casting instead of converting:

string s = "42";
int n = (int)s;  // Error! Cannot cast string to int
int n = int.Parse(s);  // Correct

Fix 3: Handle Nullable Types

Nullable value types (int?, bool?, DateTime?) cannot be implicitly assigned to their non-nullable counterparts:

Broken:

int? nullable = GetValueOrNull();
int value = nullable;  // Error: Cannot convert int? to int

Fixed — null-coalescing operator:

int value = nullable ?? 0;  // Use 0 if null

Fixed — explicit check:

if (nullable.HasValue)
{
    int value = nullable.Value;
}

Fixed — .Value (throws if null):

int value = nullable.Value;  // InvalidOperationException if null

With nullable reference types (C# 8+):

string? name = GetName();
string nonNull = name;  // Warning: possible null reference

// Fixed:
string nonNull = name ?? "default";
string nonNull = name!;  // Null-forgiving operator (you assert it's not null)

Common Mistake: Using the null-forgiving operator (!) to silence warnings without actually checking for null. This just moves the crash from compile time to runtime. Prefer ?? or explicit null checks.

Fix 4: Fix Async/Await Return Types

Forgetting await gives you a Task<T> instead of T:

Broken:

async Task<string> GetDataAsync()
{
    return await httpClient.GetStringAsync("https://api.example.com/data");
}

// Calling without await:
string data = GetDataAsync();  // Error: Cannot convert Task<string> to string

Fixed — add await:

string data = await GetDataAsync();

Fixed — make the calling method async:

// Before:
public void ProcessData()
{
    string data = GetDataAsync();  // Error
}

// After:
public async Task ProcessData()
{
    string data = await GetDataAsync();  // Works
}

Common variations:

// Wrong return type:
async Task<int> Calculate()
{
    return "42";  // Error: Cannot convert string to int
}

// Missing async keyword:
Task<string> GetName()
{
    return "Alice";  // Error: Cannot convert string to Task<string>
}

// Fixed:
async Task<string> GetName()
{
    return "Alice";  // async methods wrap the return value in Task automatically
}
// Or without async:
Task<string> GetName()
{
    return Task.FromResult("Alice");
}

Fix 5: Fix LINQ Return Types

LINQ methods return specific types that might not match your variable:

Broken:

List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };

// Where returns IEnumerable<int>, not List<int>
List<int> evens = numbers.Where(n => n % 2 == 0);  // Error!

// Select changes the element type
List<int> strings = numbers.Select(n => n.ToString());  // Error! IEnumerable<string>

// FirstOrDefault returns int?, not int (in .NET 6+)
int first = numbers.FirstOrDefault();  // May warn about nullable

Fixed — convert to the expected type:

List<int> evens = numbers.Where(n => n % 2 == 0).ToList();
List<string> strings = numbers.Select(n => n.ToString()).ToList();
int[] array = numbers.Where(n => n > 3).ToArray();

Fixed — use the correct variable type:

IEnumerable<int> evens = numbers.Where(n => n % 2 == 0);

Use var to let the compiler infer the type:

var evens = numbers.Where(n => n % 2 == 0);  // IEnumerable<int>
var first = numbers.FirstOrDefault();          // int

Fix 6: Fix Generic Covariance Issues

Generic types are not automatically covariant in C#:

Broken:

class Animal { }
class Dog : Animal { }

List<Dog> dogs = new List<Dog>();
List<Animal> animals = dogs;  // Error! List<Dog> is not List<Animal>

Fixed — use interfaces with covariance:

List<Dog> dogs = new List<Dog>();
IEnumerable<Animal> animals = dogs;  // Works! IEnumerable<T> is covariant
IReadOnlyList<Animal> readOnly = dogs;  // Also works

Fixed — create a new list:

List<Animal> animals = dogs.Cast<Animal>().ToList();
// or
List<Animal> animals = new List<Animal>(dogs);
// or with LINQ
List<Animal> animals = dogs.Select(d => (Animal)d).ToList();

Why: List<T> is invariant because it has both Add (input) and indexer (output) operations. If List<Dog> could be assigned to List<Animal>, you could add a Cat to the list through the List<Animal> reference, corrupting the List<Dog>.

IEnumerable<T> is covariant (declared with out T) because it only produces values, never consumes them.

Fix 7: Fix Enum Conversions

Enums and integers require explicit conversion:

enum Color { Red = 0, Green = 1, Blue = 2 }

// Broken:
Color c = 1;       // Error: Cannot convert int to Color
int n = Color.Red; // Error: Cannot convert Color to int

// Fixed:
Color c = (Color)1;       // Explicit cast — Green
int n = (int)Color.Red;   // Explicit cast — 0

// String to enum:
Color c = Enum.Parse<Color>("Green");  // Color.Green
if (Enum.TryParse<Color>("Green", out Color result))
{
    Console.WriteLine(result);
}

Enum to string:

string name = Color.Red.ToString();  // "Red"
string name = nameof(Color.Red);     // "Red" (compile-time constant)

Fix 8: Fix Boolean Expression Issues

Common boolean conversion errors:

// Cannot convert int to bool (unlike C/C++):
int flag = 1;
if (flag) { }  // Error in C#!

// Fixed:
if (flag != 0) { }
if (flag == 1) { }

// Cannot convert string to bool:
string input = "true";
bool b = input;  // Error!

// Fixed:
bool b = bool.Parse(input);
bool b = input.Equals("true", StringComparison.OrdinalIgnoreCase);

Conditional expression type mismatch:

// Both branches must return the same type:
var result = condition ? "hello" : 42;  // Error: string vs int

// Fixed — make types match:
var result = condition ? "hello" : "42";
// or
object result = condition ? (object)"hello" : 42;

Still Not Working?

Check for user-defined implicit conversions. Custom types can define implicit conversion operators:

public class Celsius
{
    public double Temperature { get; }

    public static implicit operator Celsius(double temp) => new Celsius(temp);
    public static explicit operator double(Celsius c) => c.Temperature;
}

Celsius c = 100.0;          // Uses implicit operator
double d = (double)c;       // Uses explicit operator

Check for interface vs concrete type. You might need to cast to an interface:

IMyInterface obj = new MyClass();  // Works if MyClass implements IMyInterface
MyClass obj2 = obj;                // Error! Need explicit cast
MyClass obj2 = (MyClass)obj;       // Works (throws if wrong type)
MyClass obj2 = obj as MyClass;     // Returns null if wrong type

Check for dynamic type. If you need late-bound behavior:

dynamic value = GetUnknownType();
int n = value;  // Runtime conversion — may throw at runtime

For C# null reference exceptions, see Fix: C# System.NullReferenceException: Object reference not set. For general type conversion in .NET, check the System.Convert class documentation.

Check your project’s nullable context. If you enabled <Nullable>enable</Nullable>, the compiler is stricter about nullable reference type assignments. Address warnings with proper null handling rather than suppressing them.

For TypeScript type errors that are similar in concept, see Fix: TypeScript cannot find name.

F

FixDevs

Solo developer based in Japan. Every solution is cross-referenced with official documentation and tested before publishing.

Was this article helpful?

Related Articles