Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • Home
  • SEARCH
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 3438002
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 18, 20262026-05-18T08:08:03+00:00 2026-05-18T08:08:03+00:00

I fully realize that what I am proposing does not follow the .NET guidelines,

  • 0

I fully realize that what I am proposing does not follow the .NET guidelines, and, therefore, is probably a poor idea for this reason alone. However, I would like to consider this from two possible perspectives:

(1) Should I consider using this for my own development work, which is 100% for internal purposes.

(2) Is this a concept that the framework designers could consider changing or updating?

I am thinking about using an event signature that utilizes a strong typed ‘sender’, instead of typing it as ‘object’, which is the current .NET design pattern. That is, instead of using a standard event signature that looks like this:

class Publisher
{
    public event EventHandler<PublisherEventArgs> SomeEvent;
}

I am considering using an event signature that utilizes a strong-typed ‘sender’ parameter, as follows:

First, define a “StrongTypedEventHandler”:

[SerializableAttribute]
public delegate void StrongTypedEventHandler<TSender, TEventArgs>(
    TSender sender,
    TEventArgs e
)
where TEventArgs : EventArgs;

This is not all that different from an Action<TSender, TEventArgs>, but by making use of the StrongTypedEventHandler, we enforce that the TEventArgs derives from System.EventArgs.

Next, as an example, we can make use of the StrongTypedEventHandler in a publishing class as follows:

class Publisher
{
    public event StrongTypedEventHandler<Publisher, PublisherEventArgs> SomeEvent;

    protected void OnSomeEvent()
    {
        if (SomeEvent != null)
        {
            SomeEvent(this, new PublisherEventArgs(...));
        }
    }
}

The above arrangement would enable subscribers to utilize a strong-typed event handler that did not require casting:

class Subscriber
{
    void SomeEventHandler(Publisher sender, PublisherEventArgs e)
    {           
        if (sender.Name == "John Smith")
        {
            // ...
        }
    }
}

I do fully realize that this breaks with the standard .NET event-handling pattern; however, keep in mind that contravariance would enable a subscriber to use a traditional event handling signature if desired:

class Subscriber
{
    void SomeEventHandler(object sender, PublisherEventArgs e)
    {           
        if (((Publisher)sender).Name == "John Smith")
        {
            // ...
        }
    }
}

That is, if an event handler needed to subscribe to events from disparate (or perhaps unknown) object types, the handler could type the ‘sender’ parameter as ‘object’ in order to handle the full breadth of potential sender objects.

Other than breaking convention (which is something that I do not take lightly, believe me) I cannot think of any downsides to this.

There may be some CLS compliance issues here. This does run in Visual Basic .NET 2008 100% fine (I’ve tested), but I believe that the older versions of Visual Basic .NET through 2005 do not have delegate covariance and contravariance. [Edit: I have since tested this, and it is confirmed: VB.NET 2005 and below cannot handle this, but VB.NET 2008 is 100% fine. See “Edit #2”, below.] There may be other .NET languages that also have a problem with this, I can’t be sure.

But I do not see myself developing for any language other than C# or Visual Basic .NET, and I do not mind restricting it to C# and VB.NET for .NET Framework 3.0 and above. (I could not imagine going back to 2.0 at this point, to be honest.)

Can anyone else think of a problem with this? Or does this simply break with convention so much that it makes people’s stomachs turn?

Here are some related links that I’ve found:

(1) Event Design Guidelines [MSDN 3.5]

(2) C# simple Event Raising – using “sender” vs. custom EventArgs [StackOverflow 2009]

(3) Event signature pattern in .net [StackOverflow 2008]

I am interested in anyone’s and everyone’s opinion on this…

Thanks in advance,

Mike

Edit #1: This is in response to Tommy Carlier’s post :

Here’s a full working example that shows that both strong-typed event handlers and the current standard event handlers that use a ‘object sender’ parameter can co-exist with this approach. You can copy-paste in the code and give it a run:

namespace csScrap.GenericEventHandling
{
    class PublisherEventArgs : EventArgs
    {
        // ...
    }

    [SerializableAttribute]
    public delegate void StrongTypedEventHandler<TSender, TEventArgs>(
        TSender sender,
        TEventArgs e
    )
    where TEventArgs : EventArgs;

    class Publisher
    {
        public event StrongTypedEventHandler<Publisher, PublisherEventArgs> SomeEvent;

        public void OnSomeEvent()
        {
            if (SomeEvent != null)
            {
                SomeEvent(this, new PublisherEventArgs());
            }
        }
    }

    class StrongTypedSubscriber
    {
        public void SomeEventHandler(Publisher sender, PublisherEventArgs e)
        {
            MessageBox.Show("StrongTypedSubscriber.SomeEventHandler called.");
        }
    }

    class TraditionalSubscriber
    {
        public void SomeEventHandler(object sender, PublisherEventArgs e)
        {
            MessageBox.Show("TraditionalSubscriber.SomeEventHandler called.");
        }
    }

    class Tester
    {
        public static void Main()
        {
            Publisher publisher = new Publisher();

            StrongTypedSubscriber strongTypedSubscriber = new StrongTypedSubscriber();
            TraditionalSubscriber traditionalSubscriber = new TraditionalSubscriber();

            publisher.SomeEvent += strongTypedSubscriber.SomeEventHandler;
            publisher.SomeEvent += traditionalSubscriber.SomeEventHandler;

            publisher.OnSomeEvent();
        }
    }
}

Edit #2: This is in response to Andrew Hare’s statement regarding covariance and contravariance and how it applies here. Delegates in the C# language have had covariance and contravariance for so long that it just feels “intrinsic”, but it’s not. It might even be something that is enabled in the CLR, I don’t know, but Visual Basic .NET did not get covariance and contravariance capability for its delegates until the .NET Framework 3.0 (VB.NET 2008). And as a result, Visual Basic.NET for .NET 2.0 and below would not be able to utilize this approach.

For example, the above example can be translated into VB.NET as follows:

Namespace GenericEventHandling
    Class PublisherEventArgs
        Inherits EventArgs
        ' ...
        ' ...
    End Class

    <SerializableAttribute()> _
    Public Delegate Sub StrongTypedEventHandler(Of TSender, TEventArgs As EventArgs) _
        (ByVal sender As TSender, ByVal e As TEventArgs)

    Class Publisher
        Public Event SomeEvent As StrongTypedEventHandler(Of Publisher, PublisherEventArgs)

        Public Sub OnSomeEvent()
            RaiseEvent SomeEvent(Me, New PublisherEventArgs)
        End Sub
    End Class

    Class StrongTypedSubscriber
        Public Sub SomeEventHandler(ByVal sender As Publisher, ByVal e As PublisherEventArgs)
            MessageBox.Show("StrongTypedSubscriber.SomeEventHandler called.")
        End Sub
    End Class

    Class TraditionalSubscriber
        Public Sub SomeEventHandler(ByVal sender As Object, ByVal e As PublisherEventArgs)
            MessageBox.Show("TraditionalSubscriber.SomeEventHandler called.")
        End Sub
    End Class

    Class Tester
        Public Shared Sub Main()
            Dim publisher As Publisher = New Publisher

            Dim strongTypedSubscriber As StrongTypedSubscriber = New StrongTypedSubscriber
            Dim traditionalSubscriber As TraditionalSubscriber = New TraditionalSubscriber

            AddHandler publisher.SomeEvent, AddressOf strongTypedSubscriber.SomeEventHandler
            AddHandler publisher.SomeEvent, AddressOf traditionalSubscriber.SomeEventHandler

            publisher.OnSomeEvent()
        End Sub
    End Class
End Namespace

VB.NET 2008 can run it 100% fine. But I’ve now tested it on VB.NET 2005, just to be sure, and it does not compile, stating:

Method ‘Public Sub
SomeEventHandler(sender As Object, e
As
vbGenericEventHandling.GenericEventHandling.PublisherEventArgs)’
does not have the same signature as
delegate ‘Delegate Sub
StrongTypedEventHandler(Of TSender,
TEventArgs As System.EventArgs)(sender
As Publisher, e As
PublisherEventArgs)’

Basically, delegates are invariant in VB.NET versions 2005 and below. I actually thought of this idea a couple of years ago, but VB.NET’s inability to deal with this bothered me… But I’ve now moved solidly to C#, and VB.NET can now handle it, so, well, hence this post.

Edit: Update #3

Ok, I have been using this quite successfully for a while now. It really is a nice system. I decided to name my “StrongTypedEventHandler” as “GenericEventHandler”, defined as follows:

[SerializableAttribute]
public delegate void GenericEventHandler<TSender, TEventArgs>(
    TSender sender,
    TEventArgs e
)
where TEventArgs : EventArgs;

Other than this renaming, I implemented it exactly as discussed above.

It does trip over FxCop rule CA1009, which states:

“By convention, .NET events have two
parameters that specify the event
sender and event data. Event handler
signatures should follow this form:
void MyEventHandler( object sender,
EventArgs e). The ‘sender’ parameter
is always of type System.Object, even
if it is possible to employ a more
specific type. The ‘e’ parameter is
always of type System.EventArgs.
Events that do not provide event data
should use the System.EventHandler
delegate type. Event handlers return
void so that they can send each event
to multiple target methods. Any value
returned by a target would be lost
after the first call.”

Of course, we know all this, and are breaking the rules anyway. (All event handlers can use the standard ‘object Sender’ in their signature if preferred in any case — this is a non-breaking change.)

So the use of a SuppressMessageAttribute does the trick:

[SuppressMessage("Microsoft.Design", "CA1009:DeclareEventHandlersCorrectly",
    Justification = "Using strong-typed GenericEventHandler<TSender, TEventArgs> event handler pattern.")]

I hope that this approach becomes the standard at some point in the future. It really works very nicely.

Thanks for all your opinions guys, I really appreciate it…

Mike

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-18T08:08:03+00:00Added an answer on May 18, 2026 at 8:08 am

    It seems Microsoft has picked up on this as a similar example is now on MSDN:

    Generic Delegates

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

This is something that I have never fully grasped in .NET as to the
I realize that this question is impossible to answer absolutely, but I'm only after
In order to fully use LinqToSql in an ASP.net 3.5 application, it is necessary
I'm fully aware that set division can be accomplished through a series of other
I've got two branches that are fully merged together. However, after the merge is
A recent talk about unordered_map in C++ made me realize that I should use
I have a webpage in ASP.NET 3.5 that will be creating WebControls dynamically. The
I'm not really sure how to phrase my issue, so I hope this isn't
I'm trying to fully understand all of Haskell's concepts. In what ways are algebraic
Suppose there is a fully populated array of data String[n][3] myData. I want to

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.