Skip to content

Add explanation for contravariance behavior with anonymous functions #47707

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Aug 5, 2025

Conversation

Copilot
Copy link
Contributor

@Copilot 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 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 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 Copilot AI requested a review from BillWagner August 4, 2025 18:01
@Copilot 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