The publish-subscribe pattern is just an observer pattern with an intermediary.
And C# events aren’t inherently the publish subscribe pattern. The intent of the publish subscribe pattern by introducing the intermediary is not requiring the publisher OR the subscriber to be aware of one another… that’s the entire point of the intermediary.
Lets give the simplest example of an event in use:
public class ButtonSubject
{
public event System.EventHandler Clicked;
void Update()
{
//test if mouse is over and pressed
if (mouseIsOverAndPressed()) Clicked?.Invoke(this, System.EventArgs.Empty);
}
}
public class ButtonActionObserver
{
public ButtonSubject Button;
void Initialize()
{
Button = new ButtonSubject();
UIElements.Add(Button);
Button.Clicked += (s,e) => {
//do stuff
};
}
}
This is a pretty basic example that you’d likely find on MSDN for say something like buttons in a WinForms situation. Or even a button here in Unity.
In this example the observer is clearly aware of the subject they are deciding to observe.
And the Button contains an indirect list of all of its observers in the form of the Clicked delegate (which underneath is just a list of all receivers. Depending the .net implementation in the form of an array or a linked list).
This follows the basic layout of the observer pattern:

Note that the ‘observerCollection’ in this, while often famliarized as a List or HashSet in many concrete examples, really just needs to come in the form of any way to store references to all observers and a way to notify those observers. The delegate facilitates this by being the collection in question.
Relationship wise those there is an observer, and a subject, and the observer directly is aware of the subject.
You could get even more tightly integrated where the button is replaced in a textfield and the observer specifically accesses the textfield’s text property during the textfields ‘onexit’ event or something. This would impose a direct reliance on the observer’s knowledge of the subject not just for registering for the event but also for acting on the event.
…
Now lets give an example of a publisher subscriber pattern… this one I’m going to use a found article for:
I want to note this article’s first sentence:
In this article it demonstrates created the publisher subscriber pattern using an event, an IPublisher, a concrete Publisher, a Subscriber, and a Message. The Subscriber has the publisher injected into its constructor in the form of the indirect IPublisher. It is not aware of WHO the publisher is… only that some publisher exists. The only thing the subscriber is concerned about is the Message it received an handling that message.
Mind you this approach is not the only way to do it. It’s just a pretty simple approach using interfaces. And of course events often have eventargs which can behave as the ‘message’ in this example. Which is why events effectively do assist in implementing a publisher subscriber pattern. But as I demonstrated above… it is not inherent to it and creating a more tightly couple example where the subscriber is well aware of its publisher can be done in events proving it is not inherent.
…
With all of that said my point when I say we’re “talking about an observer pattern”. It’d be like I said “we’re talking about fruit” where you said “no it’s an orange”. Yep… an orange is a fruit. And the publisher subscriber pattern is an observer pattern.
Furthermore the message patterns I and Brathnann above described is also a publisher subscriber relationship. The message sender is unaware of who its sending messages to, and the subscribers are unaware of who its receiving messages from.