<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/delegates-and-events-in-c-explained-p282unysa" -->

---
title: Delegates and events in C# explained | daily.dev
description: A step-by-step walkthrough of delegates and events in C#, covering how to define, assign, invoke, and unsubscribe from delegates, multicast delegate behavior,...
canonical: https://daily.dev/posts/delegates-and-events-in-c-explained-p282unysa
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: Delegates and events in C# explained | daily.dev
og:description: A step-by-step walkthrough of delegates and events in C#, covering how to define, assign, invoke, and unsubscribe from delegates, multicast delegate behavior,...
og:url: https://daily.dev/posts/delegates-and-events-in-c-explained-p282unysa
og:image: https://api.daily.dev/og/posts/p282UNYsa.png
og:image:alt: Delegates and events in C# explained
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Delegates and events in C# explained

**[Round The Code](https://daily.dev/sources/roundthecode)** · 7 min read · 15 upvotes · 0 comments

## Summary

A step-by-step walkthrough of delegates and events in C#, covering how to define, assign, invoke, and unsubscribe from delegates, multicast delegate behavior, the built-in Action, Func, and Predicate generic delegate types, using Func with async methods and Task, the event keyword's access restrictions, and building strongly typed event data with a custom EventArgs class. Code examples build an OrderService scenario throughout to illustrate each concept.

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://www.roundthecode.com/dotnet-tutorials/delegates-events-csharp-explained>

## Questions this post answers

### How do I stop code outside a class from invoking a delegate field directly in C#?

Add the event keyword to the delegate field declaration. This restricts the field so outside code can only subscribe with += or unsubscribe with -=, and attempting to call Invoke directly from outside the declaring class fails to compile with an error stating the event can only appear on the left-hand side of += or -=.

_Developers locking down class internals can revisit C# event semantics like this on daily.dev._

### Why can't I unsubscribe a lambda expression from a C# delegate with -=?

Each lambda expression creates a new delegate instance, so the instance you try to remove with -= never matches the one you added with +=. To unsubscribe successfully, declare the method separately as a named method and use that same reference for both += and -=.

_Anyone debugging stubborn event subscriptions can check this delegate behavior on daily.dev._

### What is the difference between Action, Func, and Predicate delegates in C#?

Action has no return value and its generic parameters define the invocation's argument types, Func always returns a value with the last generic parameter being the return type, and Predicate always returns a boolean given a single generic parameter type. All three are built-in generic delegate types usable for passing behavior as parameters.

_Developers choosing the right delegate type for a method signature can reference this on daily.dev._

## Similar posts on daily.dev

- [Understanding C\# Events Using a Simple ICU Example](https://daily.dev/posts/understanding-c-events-using-a-simple-icu-example-bvtejfw85) · C\# Corner · 0 upvotes · 0 comments
- [C\# Reflection: The Complete .NET 10 Guide](https://daily.dev/posts/c-reflection-the-complete-net-10-guide-xjtayoxme) · We Are .NET · 2 upvotes · 0 comments

---

Tags: [#.net](https://daily.dev/tags/.net), [#c#](https://daily.dev/tags/c#)

[View this post on daily.dev](https://daily.dev/posts/delegates-and-events-in-c-explained-p282unysa)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"TechArticle","headline":"Delegates and events in C# explained","url":"https://daily.dev/posts/delegates-and-events-in-c-explained-p282unysa","mainEntityOfPage":{"@type":"WebPage","@id":"https://daily.dev/posts/delegates-and-events-in-c-explained-p282unysa"},"datePublished":"2026-10-04T13:07:45.918Z","dateModified":"2026-10-04T13:19:31.701Z","description":"A step-by-step walkthrough of delegates and events in C#, covering how to define, assign, invoke, and unsubscribe from delegates, multicast delegate behavior,...","image":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/9ee3e7e47183d687c9cf8c89e43d6046?_a=AQAEuop","thumbnailUrl":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/9ee3e7e47183d687c9cf8c89e43d6046?_a=AQAEuop","isAccessibleForFree":true,"articleSection":"Round The Code","inLanguage":"en","publisher":{"@type":"Organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180}},"author":{"@type":"Organization","name":"Round The Code","logo":"https://media.daily.dev/image/upload/s--HmwWBSI1--/f_auto,q_auto/v1791119052/logos/roundthecode?_a=BAMAMicg0","url":"https://daily.dev/sources/roundthecode"},"commentCount":0,"discussionUrl":"https://daily.dev/posts/delegates-and-events-in-c-explained-p282unysa","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":15},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":0}],"keywords":".net,c#","timeRequired":"PT7M"}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"Round The Code","item":"https://daily.dev/sources/roundthecode"},{"@type":"ListItem","position":3,"name":"Delegates and events in C# explained"}]}
{"@context":"https://schema.org","@type":"FAQPage","@id":"https://daily.dev/posts/delegates-and-events-in-c-explained-p282unysa#faq","mainEntity":[{"@type":"Question","name":"How do I stop code outside a class from invoking a delegate field directly in C#?","acceptedAnswer":{"@type":"Answer","text":"Add the event keyword to the delegate field declaration. This restricts the field so outside code can only subscribe with += or unsubscribe with -=, and attempting to call Invoke directly from outside the declaring class fails to compile with an error stating the event can only appear on the left-hand side of += or -=. Developers locking down class internals can revisit C# event semantics like this on daily.dev."}},{"@type":"Question","name":"Why can't I unsubscribe a lambda expression from a C# delegate with -=?","acceptedAnswer":{"@type":"Answer","text":"Each lambda expression creates a new delegate instance, so the instance you try to remove with -= never matches the one you added with +=. To unsubscribe successfully, declare the method separately as a named method and use that same reference for both += and -=. Anyone debugging stubborn event subscriptions can check this delegate behavior on daily.dev."}},{"@type":"Question","name":"What is the difference between Action, Func, and Predicate delegates in C#?","acceptedAnswer":{"@type":"Answer","text":"Action has no return value and its generic parameters define the invocation's argument types, Func always returns a value with the last generic parameter being the return type, and Predicate always returns a boolean given a single generic parameter type. All three are built-in generic delegate types usable for passing behavior as parameters. Developers choosing the right delegate type for a method signature can reference this on daily.dev."}}]}
```

