How to Resolve Warning "CS0693: Type parameter has the same name as the type parameter from outer type" in C#
The Compiler Warning CS0693 is a Shadowing Warning related to Generics. The message reads: "Type parameter 'T' has the same name as the type parameter from outer type 'OuterClass<T>'".
This warning occurs when you define a generic class (e.g., MyList<T>) and then, inside that class, you define a generic method or nested class that also uses <T> as its type parameter. While valid C#, this causes Shadowing: inside the method, T refers to the method's specific type argument, effectively hiding the class's T. This creates confusing code where two different types share the same name, often leading to logical bugs.
This guide explains how to disambiguate your generic parameters.
Understanding Generic Shadowing
Imagine you have a class Wrapper<T>. When you instantiate new Wrapper<int>(), T becomes int.
If you have a method inside it declared as void DoWork<T>(T arg), this inner T is a brand new placeholder. It has no relationship to the int defined by the class. You could call DoWork<string>("hello"). Inside that method, T is string. Outside that method, T is int.
The compiler warns you because using the same name T for two completely different concepts is confusing for humans reading the code.
Scenario 1: Generic Method inside Generic Class
This is the most common occurrence. You want to write a method that takes an argument, but you accidentally redeclare the generic type syntax.
Example of error:
public class DataStore<T>
{
public T Data { get; set; }
// ⛔️ Warning CS0693: Type parameter 'T' has the same name as the outer type 'DataStore<T>'.
// This <T> creates a NEW generic type that hides the class's T.
public void Process<T>(T value)
{
System.Console.WriteLine(value);
}
}
public class Program
{
static void Main()
{
var store = new DataStore<int>();
// This is legal, but confusing!
// The class is <int>, but the method accepts <string>.
store.Process<string>("Hello");
}
}
Scenario 2: Nested Generic Classes
The same logic applies if you nest a generic class inside another generic class.
Example of error:
public class Outer<T>
{
// ⛔️ Warning CS0693: The Inner class redeclares 'T'.
public class Inner<T>
{
public T InnerValue;
}
}
Solution 1: Rename the Inner Parameter (Different Types)
If the method is supposed to handle a different type than the class (e.g., a Converter class that takes TInput and has a method converting to TOutput), simply give the inner parameter a unique name.
Solution: rename T to something else, like U, TOutput, or TMethod.
public class DataStore<T>
{
public T Data { get; set; }
// ✅ Correct: 'U' is clearly distinct from 'T'.
public void Process<U>(U value)
{
System.Console.WriteLine($"Store holds: {Data} (Type {typeof(T)})");
System.Console.WriteLine($"Method got: {value} (Type {typeof(U)})");
}
}
Solution 2: Remove the Inner Parameter (Same Type)
If your intention was for the method to use the same type as the class (e.g., Process should only accept the int defined by the class), you should not redeclare the generic parameter brackets <T>. Just use the existing T.
Solution: remove <T> from the method signature.
public class DataStore<T>
{
public T Data { get; set; }
// ✅ Correct: This method uses the class's 'T'.
// No angle brackets here.
public void Process(T value)
{
System.Console.WriteLine(value);
}
}
public class Program
{
static void Main()
{
var store = new DataStore<int>();
store.Process(100); // Valid
// store.Process("Hello"); // Compile Error (Type Safe!), which is usually what you want.
}
}
Conclusion
CS0693 is a warning about ambiguity and code clarity.
- Analyze Intent: Do you want the method to accept any type (Different from the class)? Or the specific type defined by the class?
- Different Type: Rename the inner parameter (e.g., change
<T>to<U>). - Same Type: Remove the inner parameter declaration (remove
<T>entirely from the method name).