代码之家  ›  专栏  ›  技术社区  ›  dlras2

自定义属性以确保封装

  •  2
  • dlras2  · 技术社区  · 15 年前

    我开始研究自定义属性,并提出了以下想法:如果我可以创建一个属性,它将限制变量的使用,使其仅限于所支持的属性,那该怎么办?

    [RestrictToProperty("Foo")]
    private object _foo;
    public object Foo
    {
        get { return _foo; }
        set
        {
            _foo = value;
            OnFooChanged(EventArgs.Empty);
        }
    }
    public object NotFoo
    {
        get { return _foo; }  // Warning
        set { _foo = value; } // Warning
    }
    public void Bar()
    {
        _foo = new object();  // Warning
    }
    
    // Warning: 'MyClass._foo' should not be used outside of property 'Foo'
    

    我相信这是可能的,因为 Obsolete 做类似的事情。

    [Obsolete]
    private object _foo;
    public void Bar()
    {
        _foo = new object(); // Warning: 'MyClass._foo' is obsolete
    }
    

    不幸的是,我不知道该怎么做,除了简单的运行时属性教程外,我找不到其他东西。这有可能吗?如果是,我从哪里开始?

    5 回复  |  直到 15 年前
        1
  •  3
  •   Brian Gideon    15 年前

    不,那是不可能的。 ObsoleteAttribute 有一个 special mention 在C规范中,关于编译器如何响应它。

    通过使用 auto implemented properties .

    public class Test
    {
      public object Foo { get; set; }
    }
    

    编辑: 如果需要在getter和setter中独立处理特殊逻辑,可以尝试以下代码。不过,这似乎让我非常讨厌。

    public class Test
    {
    
      private PrivateMembers Members { get; set; }
    
      public object Foo
      {
        get
        {
          return Members.Foo;
        }
        set
        {
          Members.Foo = value;
          // Do something else here.
        }
      }
    
      private class PrivateMembers
      {
        public object Foo { get; set; }
      }
    }
    
        2
  •  2
  •   Daniel Plaisted    15 年前

    你应该能够写一个 FxCop 使其成为错误或警告的规则。

        3
  •  1
  •   STW    15 年前

    不幸的是,这是不可能的。你可能想探索 PostSharp 不过,这是一个面向方面的IL weaver for.net——基本上它让源代码通过一个额外的编译层,可以注入所有额外的仪式。

        4
  •  1
  •   LukeH    15 年前

    稍微偏离主题,但您可以(ab)使用 Obsolete 实现你所需要的属性。

    将支持字段标记为已过时,以便编译器在尝试访问它时生成警告,然后 suppress those warnings 在getter/setter属性中。(相关警告为 CS0612 CS0618 )

    [Obsolete("Backing field should not be used outside of property")]
    private object _foo;
    
    public object Foo
    {
        #pragma warning disable 612, 618
        get { return _foo; }
        set
        {
            _foo = value;
            OnFooChanged(EventArgs.Empty);
        }
        #pragma warning restore 612, 618
    }
    

    这确实是一个令人讨厌的黑客行为,我并不推荐。还有其他更好的选择。例如,自定义fxcop规则、单元测试、良好的代码注释等。

        5
  •  0
  •   stakx - no longer contributing Saravana Kumar    15 年前

    不,我想这是 在语言级别不可能 . 而您可以通过 get set 访问器,不能控制对字段的访问。毕竟,这是字段和属性之间的主要区别,不是吗?

    我想 ObsoleteAttribute 由Visual Studio进行特殊处理。VS知道,每当遇到用此属性标记的类型的实例化时,它必须发出警告。因此,我认为你可能会意识到 RestrictToPropertyAttribute 在一起 使用某种类型的Visual Studio扩展/插件 .


    附笔。: 注意 在代码示例中,首先不需要显式的支持字段! 如果属性访问器不包含任何附加逻辑,那么您也可以编写:

    public int SomeProperty { get; set; }
    

    以及 SomeProperty 将自动为您创建(但它是隐藏的,因此您不能以任何其他方式访问它,除非通过属性-即您正试图实现的目标)。