Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Aug 1, 2025

This PR addresses a counterintuitive behavior with lambda expressions and delegate contravariance that was causing confusion for C# developers.

The Problem

The existing documentation explained contravariance well for named methods, but didn't cover why this seemingly equivalent code behaves differently:

// This works
var personReadContact = (Person p) => p.ReadContact();
Action<Employee> employeeReadContact = personReadContact;

// This fails with CS1661 compiler error
Action<Employee> employeeReadContact = (Person p) => p.ReadContact();

The Solution

Added a new section "Contravariance and Anonymous Functions" that explains:

  1. The Root Cause: This behavior is due to lambda expression type inference rules, not contravariance itself
  2. Why It Happens: The compiler cannot directly infer that (Person p) => p.ReadContact() should have type Action<Person> when being assigned to Action<Employee>
  3. Practical Workarounds: Explicit casting and matching parameter types
  4. Key Distinction: Difference between delegate contravariance (works after types are established) and lambda type inference (occurs during compilation)

The new documentation includes complete code examples that demonstrate both the problem and the solutions, helping developers understand this subtle but important compiler behavior.

Fixes #31678.


💬 Share your feedback on Copilot coding agent for the chance to win a $200 gift card! Click here to start the survey.


Internal previews

📄 File 🔗 Preview link
docs/csharp/programming-guide/concepts/covariance-contravariance/using-variance-for-func-and-action-generic-delegates.md Using Variance for Func and Action Generic Delegates (C#)

Copilot AI changed the title [WIP] Add explanation for anonymous function about contravariant Add explanation for contravariance behavior with anonymous functions Aug 1, 2025
Copilot finished work on behalf of BillWagner August 1, 2025 19:44
Copilot AI requested a review from BillWagner August 1, 2025 19:44
@dotnet-policy-service dotnet-policy-service bot added the okr-quality Content-quality KR: Concerns article defects (bugs), freshness, or build warnings. label Aug 4, 2025
Copy link
Member

@BillWagner BillWagner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One minor change, and this is ready.

The var keyword represents implicit typing, not explicit typing. This correction addresses the terminology issue pointed out in the code review.

Co-authored-by: BillWagner <[email protected]>
Copilot finished work on behalf of BillWagner August 4, 2025 18:01
Copilot AI requested a review from BillWagner August 4, 2025 18:01
Copilot AI requested a review from BillWagner August 4, 2025 18:17
Copilot finished work on behalf of BillWagner August 4, 2025 18:17
Copy link
Member

@BillWagner BillWagner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is now ready for final review.

@BillWagner BillWagner marked this pull request as ready for review August 4, 2025 18:18
@BillWagner BillWagner requested a review from a team as a code owner August 4, 2025 18:18
@BillWagner BillWagner requested a review from tdykstra August 4, 2025 18:19
Co-authored-by: Genevieve Warren <[email protected]>
@BillWagner BillWagner enabled auto-merge (squash) August 5, 2025 14:06
@BillWagner BillWagner merged commit dc05bd5 into main Aug 5, 2025
10 checks passed
@BillWagner BillWagner deleted the copilot/fix-31678 branch August 5, 2025 14:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

advanced-concepts/subsvc dotnet-csharp/svc okr-quality Content-quality KR: Concerns article defects (bugs), freshness, or build warnings.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add explanation for anonymous function about contravariant

3 participants