我对NHibernate的感受(2):何必到处都virtual

📅 2026/7/6 3:35:13
我对NHibernate的感受(2):何必到处都virtual
要求类中所有的公开成员public/protected都是virtual是因为NHibernate想要保证在“访问任何公开成员”之前数据已经被加载了。也就是说无论您是想调用它的ToString方法还是您自己写的辅助方法/属性在真正进入您自定义的逻辑之前数据肯定已经存在了——例如存在于私有的域字段中public class Article { private string m_tagNames public virtual string TagNames { get { return this.m_tagName; } set { this.m_tagNames value; } } public void DoSomethingWithTagNames() { Console.WriteLine(this.m_tagNames); } }虽然NHibernate可以在TagNames属性第一次访问时加载数据但是如果我们的DoSomethingWithTagNames方法直接访问m_tagNames字段数据自然无法加载了。因此NHibernate必须确保有能力在代理类中覆盖DoSomethingWithTagNames方法才行。这就是virtual方法的由来。但是在我看来我们真的有多少情况会去访问私有字段呢事实上对于大部分情况我们会使用C#中“自动属性”特性来定义属性这样自然只有属性没有字段。即使我们使用了自定义的私有字段来保存属性的值NHibernate也可以“叮嘱”我们应该访问属性而不要直接访问私有字段——其实在编程上两者并没有差别。现在这样被强迫的感觉不好。不过昨天我忽然想到这似乎也是可以理解NHibernate这么做的原因因为Hibernate要照顾到Java语言开发人员的使用感受——请注意是Hibernate没有N。不管怎么说NHibernate是从Hibernate移植过来的。NHiberante的主力开发人员Oren Eini曾在博客中写道可惜一时没找到NHiberante刻意与Hibernate的实现保持同步这样容易进行双向的同步例如Hibernate解决了一些bug或性能问题也可以较为轻易地在NHibernate上修补。不过这还是没有解释为什么Hibernate要一切都是virutal的原因啊。其实您只要看一下这段Java代码就应该明白了public class Product { private String m_tagNames; public String getTagNames() { return this.m_tagNames; } public String setTagNames(String value) { this.m_tagNames value; } }这是上面C#中Product的等价Java代码。由于Java里没有“属性”概念因此Java语言自身一直有一个“约定”getXxx和setXxx两个方法即为一个属性。这个约定用在很多地方如IDE就会把它当作是一个属性方便设置及导航框架在进行序列化时候也知道哪些东西是“属性”。这“约定”本没有问题但是这就给Java开发人员造成了一定困扰使用起来实在是太麻烦了。例如Product有个属性叫做ViewCount我们想要把它加1在C#中我们可以写this.ViewCount;而在Java中则必须是this.setViewCount(this.getViewCount() 1);因此如果是你的话在写Java代码的时候是愿意使用getXxx()这样的方法还是直接访问类中的私有字段因此我认为是Java语言的特性导致Java开发人员倾向于直接访问类中的私有字段从而导致Hibernate需要避免未加载的私有字段进一步导致Hibernate的代理类会去覆盖所有的公开方法只有方法因为Java语言没有“属性”——最终由于NHibernate在“统一大业”上的策略使得我