【问题标题】:C#: How to Implement and use a NotNull and CanBeNull attributeC#:如何实现和使用 NotNull 和 CanBeNull 属性
【发布时间】:2013-10-31 22:28:21
【问题描述】:

我想让程序员和我自己知道一个方法不需要null,如果你还是发送null给它,结果不会很漂亮。

Lokad Shared Libraries 中有一个 NotNullAttribute 和一个 CanBeNullAttribute,在 Lokad.Quality 命名空间中。

但它是如何工作的?我查看了这两个属性的源代码,它看起来像这样:

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Parameter |
                AttributeTargets.Property | AttributeTargets.Delegate |
                AttributeTargets.Field, AllowMultiple = false, Inherited = true)]
[NoCodeCoverage]
public sealed class NotNullAttribute : Attribute
{
}

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Parameter |
                AttributeTargets.Property | AttributeTargets.Delegate |
                AttributeTargets.Field, AllowMultiple = false, Inherited = true)]
[NoCodeCoverage]
public sealed class CanBeNullAttribute : Attribute
{
}

Attribute 继承的两个空类。它们是如何使用的?您是否必须查找 xml-documentation 并知道它在那里?因为我尝试制作自己的属性副本并使用 Lokad 版本,但是当我尝试直接发送空值时,我没有收到任何消息。既不是来自 ReSharper 也不是来自 VS。实际上,我有点期待。但是它们是如何使用的呢?如果我尝试在其中发送 null 的内容,我能否以某种方式让 VS 为我生成警告?还是只是在某种测试框架中使用?还是?

【问题讨论】:

  • 要评论您的具体案例,这些属性不做任何事情,只是“文档”。不过,其他答案提供了很好的选择。
  • NullableCanBeNull 的更好名称,只是说:)

标签: c# attributes null


【解决方案1】:

在中期,“代码合同”(4.0 中)将是对此的更好回答。它们现在可用(使用 academiccommercial 许可证),但将在 VS2010 中得到更多集成。这可以提供静态分析和运行时支持。

(编辑)示例:

Contract.RequiresAlways( x != null );

就这么简单...代码契约引擎在 IL 级别工作,因此它可以分析它并在构建期间或运行时调用代码引发警告/错误。为了向后兼容,如果你有现有的验证代码,你可以告诉它健全性检查在哪里结束,剩下的就交给它了:

if ( x == null ) throw new ArgumentNullException("x");
Contract.EndContractBlock();

【讨论】:

  • 看起来很流畅!它也适用于 VS 2008 吗? “更集成”是什么意思?
  • 是的;我发布的链接是针对 VS2008 变体的。通过“更集成”,我的意思是 AFAIK,它内置在 IDE 和运行时中,而不是单独的附加组件。我还没有检查(确实,不能)-但这可能可能意味着它也可以在 Express Edition 中使用(附加组件不能)。
  • 酷。你试过这个插件了吗?易于安装和使用?在生产环境中使用是否安全? (如果我添加它,其他员工会杀了我吗?:P)
  • 我刚刚启动了 VS2010 的旧 CTP 版本,但当最后一个 CTP 发布时,“位”似乎还没有准备好。告诉你什么,我会试试看;-p
【解决方案2】:

这可以通过AOP 来完成,由此Advice 在运行时验证方法参数是否为空以及是否允许空值。有关 AOP,请参阅 PostSharpSpring.NET

至于 ReSharper,见Annotated Framework

我们分析了很大一部分 .NET Framework 类库以及 NUnit Framework,并使用来自 JetBrains.Annotations 命名空间的一组自定义属性通过外部 XML 文件对其进行了注释,具体来说:

  • StringFormatMethodAttribute(用于将格式字符串作为参数的方法)
  • InvokerParameterNameAttribute(用于带有字符串字面量参数且应与调用者参数之一匹配的方法)
  • AssertionMethodAttribute(用于断言方法)
  • AssertionConditionAttribute(用于断言方法的条件参数)
  • TerminatesProgramAttribute(用于终止控制流的方法)
  • CanBeNullAttribute(对于可以为空的值)
  • NotNullAttribute(对于不能为空的值)

【讨论】:

  • 您可以从 NuGet 获取 ReSharper 注释:nuget.org/packages/JetBrains.Annotations
  • 但是 resharper 注释只是 resharper 可读的注释。它们在运行时不会被检查
  • 你的链接不再指向引用的文本,引用的文本已经移到External Annotations,虽然由于OP是注释他自己的代码,外部注释是不合适的。
【解决方案3】:

这些注释适用于 ReSharper,并从 JetBrains.Annotations 命名空间复制而来。框架可以将它们放在自己的命名空间中,但是,ReSharper 不会自动获取这些注释 - 您需要在选项对话框中告诉 ReSharper 使用自定义命名空间。一旦您选择了新的命名空间,ReSharper 的分析将获取属性并为您提供突出显示和警告。

【讨论】:

    【解决方案4】:

    正如Anton Gogolev 所指出的,可以使用 PostSharp 创建属性。(请注意,CodeContract 在方法体内使用静态方法调用)

    2013 年 2 月更新:PostSharp 的新 3.0 版本(目前处于测试阶段)将支持 Validating parameters, fields and properties

    1) 文章validate-parameters-using-attributes 实现了

    公共类 NotEmpty : ParameterAttribute

    公共类 NotNull : ParameterAttribute

    [AttributeUsage(AttributeTargets.Parameter)]

    公共抽象类ParameterAttribute:属性

    {

    public abstract void CheckParameter(ParameterInfo parameter, object value); 
    

    }

    还需要具有方法边界方面的方法属性来处理参数属性。

    2) 在文章的评论中有指向 very similar implementation 的链接,用于表示 NonNull/NonEmpty   

    [return: NonNull] public SomeObject SomeMethod([NonNull] AnotherObject param1)

    源代码位于google code Torch/DesignByContract

    3) 在http://badecho.com/2011/11/validating-method-parameters-with-postsharp/     中描述了另一个更复杂的例子

    【讨论】:

      猜你喜欢
      • 2016-06-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-24
      • 2010-09-28
      • 2018-11-24
      • 1970-01-01
      相关资源
      最近更新 更多