C#匿名后备字段和非自动属性

5

我希望创建一个私有成员变量,即使是它所属的类也无法访问,只能通过其getter和setter进行访问。 我知道可以使用自动属性来实现这一点,例如

private int MyInt{ get; set;}

但是我希望能够修改getter和setter,例如记录该字段被设置的次数(甚至由所属类设置)。类似于这样:

private int MyInt
{
    get{ return hiddenValue; }
    set{ hiddenValue = value; Console.Out.WriteLine("MyInt has been set");}
}

"hiddenValue"是只能在getter和setter中访问的成员。

为什么?因为我是一个偏执的防御性程序员,我甚至不相信自己:p。

C#中是否可以实现这一点?如果可以,语法是什么?

谢谢。


1
努力争取这一点,有更多好的理由,而不是偏执 : )。缓存属性并不罕见,即在第一次访问时,通过数据库等获取值并存储在后备字段中,对于后续访问,getter使用该后备字段。此时,对于开发人员,特别是那些新加入项目的人来说,是否使用属性或后备字段可能不清楚。 - Anders
5个回答

6

你应该相信自己。

但是,不,你不能使一个变量如此私有,以至于封装类也看不到它。

如果你确实想要这样,你可以将该值封装在一个嵌套类中,该类将能够隐藏其自己的私有成员。

class Foo 
{
    class Bar // nested
    {
        private int _value;
        public int Value 
        {
            get { return _value; }
            set { _value = value; /* logic */ }
        }
    }
}

Foo可以实例化Bar,访问bar.Value,但无法访问_value。


4
但话说他仍然可以使用反射来更改该值,因此还不够谨慎。 - BrokenGlass
1
可惜啊,这个会在维护代码时很有用。虽然没有哪个代码是百分之百傻瓜式的,但这确实有帮助。不过,将其放入封装类中会增加太多代码复杂性和出错几率 :p - Bryan Hart
1
@Bryan,你知道什么会毁了你的一天吗?准备好了吗?不同的Foos实例可以看到彼此的私有成员。你不仅不能从一个实例中隐藏成员,也无法从同一类的另一个实例中隐藏它。 - Anthony Pegram
@BrokenGlass 是的,但他们必须付出努力来绕过访问器。这更多是为了确保在内部引起更改时仍会触发onChange事件。如何在匿名后备成员上使用反射?我已经在Java领域工作了几年,所以我正在重新熟悉C#,但我似乎记得需要成员名称才能通过反射修改它。 - Bryan Hart
@Bryan,要考虑一旦编译后,它就不是“匿名”的了。自动实现的属性可以节省您定义后备字段的麻烦,但这并不意味着没有后备字段。您只是将创建后备字段的负担转嫁给了编译器。 - Anthony Pegram
显示剩余2条评论

4

在.Net中,任何语言都不可能实现。这是好的。防御性编程固然重要,但过度谨慎会让需要维护代码的其他开发人员感到困扰。


3
需要进行防御性编程,因为其他开发人员需要维护它! - Mark H
1
我仍然喜欢使用优美的解决方案(AOP,代码合同),但当您开始检查发送器和参数是否存在空引用,并且没有打算在代码中稍后使用它们时,我会想知道为什么要这样做,这是适得其反的。 - Adrian Iftode
1
@Mark H... 没错!我总是假设在我之后处理它的人是个彻头彻尾的白痴,即使那个人就是我自己。如果我能保证访问器总是被调用,那么我就可以确定我的事件总是会被触发并且数据总是被验证过的。 - Bryan Hart

3

面向切面编程(AOP)可能会有所帮助,简而言之,它允许您在方法调用之前和/或之后注入自己选择的代码。

请查看http://code.google.com/p/easyprop/,这是一个专门设计用于监视属性更改的AOP库,并且有与自动属性一起使用的示例。

NB:我还没有使用过该库,但它似乎非常适合您的需求。


1
我认为PostSharp是更好的框架,因为它提供了AOP。 - Sumo
我现在正在研究PostSharp。虽然它不能完全解决这个问题,但总的来说看起来还是很有帮助的 :p - Bryan Hart

2

不,C#中不可能实现这一点。

你最好的选择可能是变得不那么多疑。:P


1

你正在尝试做的事,在.NET中无法实现。

即使是隐藏的后备字段也会在IL代码中可见。这意味着虽然你在设计时间(在VS中)看不到它,但在编译后它仍会存在。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接