C# 为什么可以';我不能将事件标记为NotNull吗? 公共类事件总线 { [NotNull]//注释对此声明类型无效 私有静态事件-动作事件; 静态事件总线() { //我们总是有一个不做任何事情的事件处理程序,所以我们不必担心空检查和竞争条件 事件+=T=>{}; }

C# 为什么可以';我不能将事件标记为NotNull吗? 公共类事件总线 { [NotNull]//注释对此声明类型无效 私有静态事件-动作事件; 静态事件总线() { //我们总是有一个不做任何事情的事件处理程序,所以我们不必担心空检查和竞争条件 事件+=T=>{}; },c#,visual-studio-2012,resharper,C#,Visual Studio 2012,Resharper,正如在评论中所看到的,我明确地不想处理到处检查事件的null。这可以通过在构造时分配一个从未调用的默认不做任何事情事件来解决。Resharper无法自动解决这一问题并不奇怪,因此我想用NotNull注释对其进行注释。不幸的是,我似乎NotNull不能应用于事件,但每当我调用我的事件时,Resharper都会毫不犹豫地警告我“可能”System.NullReferenceException“ 如果resharper注意到错误,应该可以通过注释来避免错误。如果您想这样做,可以更改属性(添加标志Att

正如在评论中所看到的,我明确地不想处理到处检查事件的null。这可以通过在构造时分配一个从未调用的默认不做任何事情事件来解决。Resharper无法自动解决这一问题并不奇怪,因此我想用NotNull注释对其进行注释。不幸的是,我似乎NotNull不能应用于事件,但每当我调用我的事件时,Resharper都会毫不犹豫地警告我“可能”System.NullReferenceException“


如果resharper注意到错误,应该可以通过注释来避免错误。

如果您想这样做,可以更改属性(添加标志
AttributeTargets.Event
)以在版本8中添加对事件的支持

public class EventBus<T>
{
    [NotNull] // annotation not valid on this declaration type
    private static event Action<T> Events;

    static EventBus()
    {
        // we always have a do-nothing event handler so we don't have to worry about null checks and race conditions
        Events += T => { };
    }
我认为他们这样做是因为他们认为对于事件,最好在引发之前检查它是否为null。如果您尝试使用Resharper生成事件invocator,它将生成如下内容:

namespace JetBrains.Annotations
{
    /// <summary>
    /// Indicates that the value of the marked element could never be <c>null</c>
    /// </summary>
    /// <example><code>
    /// [NotNull] public object Foo() {
    ///   return null; // Warning: Possible 'null' assignment
    /// }
    /// </code></example>
    [AttributeUsage(
      AttributeTargets.Method | AttributeTargets.Parameter |
      AttributeTargets.Property | AttributeTargets.Delegate |
      AttributeTargets.Field | AttributeTargets.Event, AllowMultiple = false, Inherited = true)]
    public sealed class NotNullAttribute : Attribute { }
或者,您可以明确实施您的事件:

protected virtual void OnMyEvent()
{
    var handler = MyEvent;
    if (handler != null) 
        handler();
}
[NotNull]
私有静态操作_eventsInternal=obj=>{};
私有静态事件操作事件
{
添加{u eventsInternal+=value;}
删除{u eventsInternal-=value;}
}
受保护的静态无效事件(T参数)
{
_事件内部(arg);
}

如果要将null分配给不可理解的默认值,为什么还要麻烦检查null?如果这是必须的,那么为什么不直接将事件处理程序分配给内联的空委托实例?
私有静态事件操作事件=\u=>{};
您是对的,我应该以内联方式而不是在构造函数中初始化它,因为这样会更清楚。默认设置的原因是,我不必检查null。目标是,当没有连接事件处理程序时,事件仍然可以“调用”
Events()
。感谢您提供有关添加我自己的NotNullAttribute的提示。就我个人而言,我认为最好将字段标记为NotNull并对其进行初始化,而不是在调用事件的每个位置都检查null。在添加调用时,有人忘记进行检查的可能性较小。此外,在检查事件是否存在竞争时,很容易忽略微妙的竞争条件null,然后调用它,这是bug出现的另一个机会。
[NotNull]
private static Action<T> _eventsInternal = obj => { };

private static event Action<T> Events
{
    add { _eventsInternal += value; }
    remove { _eventsInternal -= value; }
}

protected static void OnEvents(T arg)
{
    _eventsInternal(arg);
}