事件签名的.NET - 使用强类型'发件人'? [英] Event Signature in .NET -- Using a Strong Typed 'Sender'?

查看:333
本文介绍了事件签名的.NET - 使用强类型'发件人'?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我充分认识到,我的建议不符合.NET的指导方针,并因此可能对仅仅因为这个原因一个贫穷的想法。不过,我想从两个可能的角度考虑这个问题:

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)我应该考虑使用这个对我自己的开发工作,这是100%,供内部使用。

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

(2)这是一个概念,框架设计人员可以考虑改变或更新?

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

我想到的不是键入它作为对象,这是当前的.NET设计模式有关使用事件的签名,利用强大的类型化'发件人'。也就是说,不是使用标准事件的签名看起来像这样,:

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:

首先,定义一个StrongTypedEventHandler:

First, define a "StrongTypedEventHandler":

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

这是并不是所有从动作&LT不同,TSender,TEventArgs&gt;中,但通过使用的 StrongTypedEventHandler ,我们实施了TEventArgs来源于 System.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.

接着,作为一个例子,我们可以利用StrongTypedEventHandler在出版类,如下所示:

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")
        {
            // ...
        }
    }
}

我这样做完全意识到这打破了标准.NET事件处理模式;但是,请记住,逆变将能使用户使用传统的事件处理的签名,如果需要的:

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.

有可能会出现一些CLS合规性问题在这里。这并不运行在Visual Basic .NET 2008年100%的罚款(我测试过),但我相信,Visual Basic .NET中的至2005年的旧版本没有委托协变和逆变。 的有可能是其他.NET语言也有这样的问题,我不能肯定。

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. There may be other .NET languages that also have a problem with this, I can't be sure.

不过,我不认为自己开发比C#或Visual Basic .NET以外的任何语言​​,我不介意把它限制为C#和VB.NET用于.NET Framework 3.0及以上。 (我不能想象回到2.0在这一点上,是诚实的。)

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)事件设计指南[MSDN 3.5]

(2)<一href="http://stackoverflow.com/questions/809609/c-simple-event-raising-using-sender-vs-custom-eventargs">C#简单的事件饲养 - 使用发件人与自定义的EventArgs [2009计算器]

在.NET(3)事件签名模式[计算器2008]

我对这个感兴趣的任何人的,每个人的意见了......

I am interested in anyone's and everyone's opinion on this...

在此先感谢,

迈克

编辑#1:这是响应<一个href="http://stackoverflow.com/questions/1046016/event-signature-in-net-using-a-strong-typed-sender/1046104#1046104">汤米CARLIER的帖子:

下面是一个完整的工作的例子,说明两者强类型的事件处理程序,并使用一个'对象发件人的参数在目前的标准事件处理程序共存这一做法。您可以复制,粘贴在code,并给它一个运行:

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();
        }
    }
}

编辑#2:这是响应<一个href="http://stackoverflow.com/questions/1046016/event-signature-in-net-using-a-strong-typed-sender/1046041#1046041">Andrew野兔的有关协变和逆变,以及如何声明它适用于这里。在C#语言的代表有过协变和逆变这么久,就觉得这是内在,但事实并非如此。它甚至可能是一些在CLR的启用,我不知道,但Visual Basic .NET中没有得到协变和逆变能力的代表,直到在.NET Framework 3.0(2008年VB.NET)。其结果,可视Basic.NET用于.NET 2.0及以下将不能够利用这种方法

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.

例如,上述例子可以被翻译成VB.NET如下:

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可以运行它100%的罚款。但我现在已经测试了VB.NET 2005,只是可以肯定,它并不能编译,指出:

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:

法公用Sub   SomeEventHandler(发送者为对象,E   如   vbGenericEventHandling.GenericEventHandling.PublisherEventArgs)   不具有相同的签名   委托委托子   StrongTypedEventHandler(中TSender,   TEventArgs作为System.EventArgs)(发件人   作为出版商,E作为   PublisherEventArgs)

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)'

基本上,代表们不变的VB.NET版本2005和下面。其实我觉得这个想法在几年前,但VB.NET无力解决这一困扰我...但我现在已经搬到牢固到C#和VB.NET现在可以处理,所以,好了,因此这一职务。

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.

编辑:更新#3

好吧,我一直在用这个相当成功,而现在。这真的是一个很好的系统。我决定把我的名字StrongTypedEventHandler为GenericEventHandler,定义如下:

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.

它确实被绊倒的FxCop规则CA1009,其中规定:

It does trip over FxCop rule CA1009, which states:

按照惯例,.NET事件有两个   指定事件参数   发送者和事件数据。事件处理   签名应遵循如下形式:   无效MyEventHandler(对象发件人,   EventArgs的)。在'发件人'参数   始终是System.Object类型,即使   如果它是可以采用一个更   特定类型。在E参数   始终类型System.EventArgs的。   不提供的事件数据的事件   应使用System.EventHandler   委托类型。事件处理程序返回   无效,使他们能够发送的每个事件   到多个目标的方法。任何值   由目标返回将丢失   之后的第一个电话。

"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."

当然,我们知道这一切,都打破了规则,反正。 (所有的事件处理程序可以使用标准的'对象发件人'在他们的签名,如果pferred在任何情况下,$ P $ - 这是一个非重大更改)

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.)

所以使用了燮pressMessageAttribute 的伎俩:

[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.

感谢你的意见,大家好,我真的AP preciate吧...

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

迈克

推荐答案

看来微软已经拿起这是一个类似的例子,现在MSDN上:

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

泛型委托

这篇关于事件签名的.NET - 使用强类型'发件人'?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆