【问题标题】:How to warn if a property is accessed without being initialized, by adding an attribute?如何通过添加属性来警告是否在未初始化的情况下访问属性?
【发布时间】:2012-01-27 12:41:57
【问题描述】:

我想要一些技术来自动替换以下代码:

[WarnIfGetButUninitialized]
public int MyProperty {get; set; }

有了这个:

/// <summary>
/// Property which warns you if its value is fetched before it has been specifically instantiated.
/// </summary>
private bool backingFieldIsPopulated = false;
private int backingField;
public int MyProperty { 
    get
    {
        if (backingFieldIsPopulated == false)
        {
            Console.WriteLine("Error: cannot fetch property before it has been initialized properly.\n");
            return 0;
        }
        return backingField;
    }
    set { 
        backingField = value;
        backingFieldIsPopulated = true;
    }
}       

我更喜欢在编译时工作的解决方案,因为反射很慢。

我知道面向方面的编程 (AOP) 会做到这一点(例如 PostSharp 和 CciSharp),但如果有任何其他方法可以实现这一点,我会很感兴趣。

更新

请参阅How to use PostSharp to warn if a property is accessed before it has been initialized?,其中包含一些示例代码的链接,这些示例代码演示了使用 PostSharp 的技术。

【问题讨论】:

  • 我想说你最简单的选择是使用 PostSharp 或 Unity IoC,它们可以做有限的 AOP。

标签: c# .net visual-studio


【解决方案1】:

属性只是将元数据添加到类和类成员中——它们本身什么也不做。

对装饰成员的操作是通过反射完成的——在一些现有的工具中对此有一些支持,但对自定义属性将没有这样的支持。

简而言之 - 如果编译器尚不支持属性,则无法在编译时检查属性。

但是,您可以创建自己的 code snippets 以使此类代码更易于编写和创建。

【讨论】:

  • 我可以使用任何面向方面编程 (AOP) 实用程序,例如 PostSharp 或 CciSharp。问题是 - 如何?
  • @Gravitas - 是的,尽管这是编译之前的额外步骤(根据我的经验,PostSharp 相当慢)。
  • 我假设您的意思是在编译时稍慢(但在运行时相同)。不是直接把IL注入到编译好的程序集中,所以结果和自己写的一样吗?
  • @Gravitas - 在编译期间非常慢。它确实会进行 IL 编织 - 就我个人而言,我发现结果掩盖了实际生产的内容。
  • AOP 仅适用于横切关注点,例如在异常上添加日志记录。重点是模糊样板代码,因为它使代码更清晰。但是,我同意它可能会被滥用(我猜就像 C# 中的任何东西一样)。
【解决方案2】:

T4 模板可用于代码生成。我自己还没有实现,但是 T4 模板用于 C# 中的代码生成。来自斯科特·汉塞尔曼的更多信息

http://www.hanselman.com/blog/T4TextTemplateTransformationToolkitCodeGenerationBestKeptVisualStudioSecret.aspx

【讨论】:

  • 我目前正在使用 T4。但是,T4 编辑器与 Visual Studio / ReSharper 提供的编辑器相比略有不足(为什么 T4 不能与 Visual Studio 中的内置编辑器一起使用?)。
【解决方案3】:

通过编译只检查一些属性。 ObsoleteAttribute 和 ConditionalAttribute 是其中的两个。 使用 Resharper,您可以获得此类警告。我不知道有任何其他工具可以做到这一点。

【讨论】:

    【解决方案4】:

    您可以执行类似于 .NET 的 Lazy 的实现,但是在使用该属性时这需要更多的冗长。像这个非线程安全的例子:

    public class WarnIfGetButUninitialized<T>
    {
        T _property;
        public T Value
        {
            get
            {
                if(_property == null)
                {
                    Console.WriteLine("Error: cannot fetch property before it has been initialized properly.\n");
                    return default(T);
                }
                return _property;
            }
            set { _property = value; }
        }
    }
    

    【讨论】:

      【解决方案5】:

      来自 PostSharp 论坛上的 Gael Fraiteur(感谢 Gael!):

      您必须使用实现的 LocationInterceptionAspect IInstanceScopedAspect。字段“backingFieldIsPopulated”变为 方面的字段。

      你可以在这个例子中找到灵感:

      http://doc.sharpcrafters.com/postsharp-2.1/Content.aspx/PostSharp-2.1.chm/html/d3631074-e131-467e-947b-d99f348eb40d.htm

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-01-25
        • 2021-05-22
        • 1970-01-01
        • 2016-10-29
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多