0
0
C Sharp (C#)programming~10 mins

Contravariance with in keyword in C Sharp (C#) - Step-by-Step Execution

Choose your learning style9 modes available
Concept Flow - Contravariance with in keyword
Define interface with 'in' keyword
Create base and derived classes
Assign derived type to base type variable
Call method accepting base type
Contravariance allows safe assignment
Contravariance lets you use a less derived type where a more derived type is expected, enabled by the 'in' keyword in generic interfaces.
Execution Sample
C Sharp (C#)
interface IContravariant<in T> { void Set(T item); }
class Animal {}
class Dog : Animal {}
class ContravariantSetter<T> : IContravariant<T> { public void Set(T item) { } }
IContravariant<Animal> animalSetter = new ContravariantSetter<Dog>();
animalSetter.Set(new Animal());
Shows how contravariance allows assigning IContravariant<Dog> to IContravariant<Animal> using 'in' keyword.
Execution Table
StepActionType involvedAssignment Valid?Reason
1Define interface IContravariant<in T>T is contravariantN/AAllows T to be used as input parameter type
2Create classes Animal and Dog : AnimalDog inherits AnimalN/ADog is subtype of Animal
3Create instance of ContravariantSetter<Dog>IContravariant<Dog>N/AConcrete implementation for Dog
4Assign to IContravariant<Animal> variableIContravariant<Dog> to IContravariant<Animal>No'in' keyword allows contravariance but assignment is from less derived to more derived, which is invalid
5Call Set(new Animal()) on variableSet(Animal)Runtime errorDog setter expects Dog, Animal passed (contravariance only safe for input types, but method expects Dog)
6Call Set(new Dog()) on variableSet(Dog)SuccessDog instance matches expected type
💡 Execution stops after method calls; contravariance allows assignment from more derived to less derived generic types, but method parameter types must be compatible at runtime.
Variable Tracker
VariableStartAfter Step 3After Step 4After Step 5
animalSetternullContravariantSetter<Dog> instanceAssignment invalid, no assignment occursMethod called with Animal or Dog instance
Key Moments - 2 Insights
Why can I assign IContravariant<Dog> to IContravariant<Animal> but not vice versa?
Because the 'in' keyword makes T contravariant, allowing assignment from more derived to less derived types (Animal to Dog), but not the other way around.
Why does calling Set(new Animal()) cause a runtime problem?
Because the actual implementation expects Dog, but Animal is passed, which is not safe. Contravariance applies to assignment compatibility, but method calls must respect actual parameter types.
Visual Quiz - 3 Questions
Test your understanding
Look at the execution_table at step 4, what does the 'in' keyword allow?
AAssign unrelated types
BAssign IContravariant<Dog> to IContravariant<Animal>
CAssign IContravariant<Animal> to IContravariant<Dog>
DNo assignment allowed
💡 Hint
Check the 'Assignment Valid?' column at step 4 in execution_table
At which step does calling Set with an Animal instance cause a problem?
AStep 5
BStep 3
CStep 4
DStep 6
💡 Hint
Look at the 'Reason' column for runtime errors in execution_table
If we remove the 'in' keyword, what happens to the assignment in step 4?
AIt causes runtime error
BIt becomes invalid
CIt remains valid
DIt compiles but fails at runtime
💡 Hint
Recall that 'in' enables contravariance; without it assignment is invalid (see step 4)
Concept Snapshot
Contravariance with 'in' keyword:
- Use 'in' on generic type parameter to allow contravariance
- Allows assignment from more derived to less derived generic types
- Safe only for input (method parameter) types
- Enables flexible and type-safe assignments
- Method calls must respect actual parameter types
Full Transcript
This visual execution shows how contravariance works in C# using the 'in' keyword on generic interfaces. First, an interface IContravariant with 'in T' is defined, allowing T to be used only as input. Then, classes Animal and Dog (which inherits Animal) are created. An instance of ContravariantSetter<Dog> is assigned to a variable of type IContravariant<Animal> thanks to contravariance. Calling Set with a Dog instance works fine, but calling Set with an Animal instance causes a runtime problem because the implementation expects Dog. The key is that contravariance allows assignment compatibility but method calls must respect actual parameter types. This helps write flexible and safe code when dealing with inheritance and generics.