[你必须知道的.NET]第三十四回,object成员,不见了!

anytao.net | 《你必须知道的.NET》网站 | Anytao技术博客 

发布日期:2009.10.30 作者:Anytao
© 2009 Anytao.com ,Anytao原创作品,转贴请注明作者和出处。

 

在.NET世界了,object是公认的造物主,其麾下的7大成员,个顶个的横行在任何系统的任何代码角落。

public class Object
{
    public Object();
    public virtual bool Equals(object obj);
    public static bool Equals(object objA, object objB);
    public virtual int GetHashCode();
    public Type GetType();
    protected object MemberwiseClone();
    public static bool ReferenceEquals(object objA, object objB);
    public virtual string ToString();
}

关于object的故事,有很多很多。而今天的故事则着眼于“为熟悉的朋友做点儿不熟悉的事儿”。相信吗?我的Object成员不见了,不信你可以欣赏一下消失了的object成员。

o_anytao-insidenet-34-01[1]

哈哈!清新多了吧,比起下面常见的编码方式:

o_anytao-insidenet-34-02[1]

是不是让人不知所挫。大概说来,任何时候,在长长的成员方法列表中,你总能看到他们的身影,谁让object是万物的基类呢?不过,有些时候,我可能希望眼根清净,屏蔽掉不会使用的父类成员,使得方法调用变得更加简洁,就像上面的IObject成员一样。

那么这一切是如何做到的呢?虽然我是一个诚实的人,但是其实这是一次赤裸裸的欺骗,而行骗的家伙就是将要闪亮登场的:

namespace System.ComponentModel
{
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Delegate)]
    public sealed class EditorBrowsableAttribute : Attribute
    {
    }
}

是的,正是System.CompentModel.EditorBrowsableAttriute。以上例而言,我其实为AnyObject类实现了下面的编码:

public interface IObject : IAnyObject
{
    void About();
}

 

public class AnyObject : IObject
{
    public void About()
    {
    }
}

其中的核心在于IAnyObject的定义:

namespace Anytao.Core.Common
{
    /// <summary>
    /// A common interface for any object
    /// </summary>
    [EditorBrowsable(EditorBrowsableState.Never)]
    public interface IAnyObject
    {
        [EditorBrowsable(EditorBrowsableState.Never)]
        bool Equals(object obj);

        [EditorBrowsable(EditorBrowsableState.Never)]
        int GetHashCode();

        [EditorBrowsable(EditorBrowsableState.Never)]
        Type GetType();

        [EditorBrowsable(EditorBrowsableState.Never)]
        string ToString();
    }
}

在通常的情况下,我的Anytao.Core.Common基础组件中都提供一个通用的IAnyObject接口,该接口的作用就是将object成员魔术般的隐藏掉,就如同本文开始的IObject一样。

所以,我们回到System.CompentModel.EditorBrowsableAttriute特性,就可以了解到其作用就是:标识一个类或者属性在编辑器中的可见性。
那么,难道他们真的消失了吗?继续应用一开始的代码:
class Program
{
    static void Main(string[] args)
    {
        IObject obj = new AnyObject();

        Console.WriteLine(obj.ToString());
    }
}

我们发现虽然ToString对obj是不可见的,但是运行时调用仍然没有问题,所以,总体说来System.ComponentModel.EditorBrowsableAttribute只是一个障眼法,在此实现了对Visual Studio智能感知的控制。其中EditorBrowsableState选项主要包括了:

  • Advanced,针对高级成员的选项设置,同样的方式可以应用Visual Studio的Options->Text Editor->C#->General的Hide advanced members设置。
  • Always,总是可见。
  • Never,总是不可见。

注意:在Visual C#中,EditorBrowsableAttribute并不对同一程序集的成员有效。

 

还等什么?也去试试吧?另外关于编辑器,还有很多好玩的特性值得挖掘,贵在发现的力量。

 

参考文献

 

更多闲言碎语,关注anytao.net

 

anytao | © 2009 Anytao.com

2009/10/30 | http://anytao.cnblogs.com/ | http://www.anytao.net/blog/post/2009/10/29/anytao-insidenet-34-object-members-hide.aspx

本文以“现状”提供且没有任何担保,同时也没有授予任何权利。 | This posting is provided "AS IS" with no warranties, and confers no rights.

本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

9
0
(请您对文章做出评价)
« 上一篇:[你必须知道的.NET]第三十三回,深入.NET 4.0之,Lazy<T>点滴
» 下一篇:[开发故事]第五回,用想要的域名运行你的本地Web应用
posted @ 2009-10-30 00:47 Anytao 阅读(4256) 评论(65)  编辑 收藏 网摘 所属分类: 01 [你必须知道的.NET]

  回复  引用  查看    
#1楼2009-10-30 00:57 | Jeffrey Zhao      
厉害,这你是如何知道的亚?
  回复  引用  查看    
#2楼2009-10-30 01:05 | 不常在      
学习了 买了本 你必须知道的.NET 正在学习中
  回复  引用  查看    
#3楼2009-10-30 01:13 | Ivony...      
引用Jeffrey Zhao:厉害,这你是如何知道的亚?



呃,其实很多控件(组件)开发者接触这些东西会比较多,老赵是不是不玩控件的?

话说我做控件的时候也注意到过这个特性,不过当时就是注意到了,知道有啥用了,没进一步挖出这样的应用。

  回复  引用  查看    
#4楼2009-10-30 01:15 | Jeffrey Zhao      
@Ivony...
呃……真不写控件的……

  回复  引用    
#5楼2009-10-30 01:19 | javascript[未注册用户]
只用过winform 组件的 BrowsableAttribute,那只是属性窗口里隐藏,太常见乐,你这个代码编辑器的智能感知隐藏,还真不知道,更没试过,不过除了好玩有什么实用价值呢?
  回复  引用    
#6楼2009-10-30 01:21 | javascript[未注册用户]
@Ivony...
控件的不是EditorBrowsableAttribute,而是BrowsableAttribute,只管属性窗口,没管代码编辑器。

  回复  引用  查看    
#7楼2009-10-30 01:23 | cnhzlt      
开眼界了
  回复  引用  查看    
#8楼2009-10-30 01:34 | Ivony...      
引用javascript:
@Ivony...
控件的不是EditorBrowsableAttribute,而是BrowsableAttribute,只管属性窗口,没管代码编辑器。



研究Browsable的时候我就扫到了这个EditorBrowsable。。。。

我当时在找让某个属性在ASP.NET标签中消失的方法。。。。。

感觉这玩意儿也是给控件开发者玩的,否则谁会找到那里去。。。

  回复  引用  查看    
#9楼2009-10-30 02:21 | 颜昌钢      
代码编辑器智能感知隐藏了,但是,如果知道方法名,直接写出来,还是可以编译通过的
  回复  引用    
#10楼2009-10-30 04:09 | 久永1[未注册用户]
唉!弄过无数次想实现,原来是这么搞得~
  回复  引用    
#11楼2009-10-30 07:14 | 木色[未注册用户]
看过楼主的书,很强
受教了.

  回复  引用  查看    
#12楼2009-10-30 08:25 | Beginor      
通过编辑器设置可以选择是否显示高级属性的
  回复  引用  查看    
#13楼2009-10-30 08:40 | 阿不      
细致
  回复  引用  查看    
#14楼2009-10-30 08:52 | 一风      
为了不在智能感应中显示几个成员而要让所有的类型都实现一个接口,这未免也太那个了点吧。
  回复  引用  查看    
#15楼2009-10-30 09:04 | 一线风      
什么时候书的版本更新呀?

  回复  引用  查看    
#16楼2009-10-30 09:10 | James.Ying      
这个好玩的,收藏一下
  回复  引用  查看    
#17楼2009-10-30 09:11 | CoolCode      
这都让你想到了,厉害
  回复  引用  查看    
#18楼2009-10-30 09:20 | GWPBrian      
呵呵,厉害,问下,为什么要把Object的成员隐藏起来啊?这种把成员隐藏起来有什么好处吗?
  回复  引用  查看    
#19楼2009-10-30 09:21 | Yankee      
佩服博主的文笔,呵呵
  回复  引用  查看    
#20楼2009-10-30 09:32 | Jerry Qian      
vs2010智能感应现在现在变得模糊了啊.
http://weblogs.asp.net/scottgu/archive/2009/10/22/vs-2010-code-intellisense-improvements-vs-2010-and-net-4-0-series.aspx
官方越显示越多,你越显示越少啊.哈哈.

  回复  引用  查看    
#21楼2009-10-30 09:51 | Franking      
这个……可以没有。。。
  回复  引用  查看    
#22楼2009-10-30 09:54 | 飞林沙      
涛哥连这个都发现了.... 学习了....
  回复  引用  查看    
#23楼2009-10-30 09:54 | 飞林沙      
@GWPBrian

只是举一个例子,呵呵,不过具体什么用说实话我真没想到.... 如果想隐藏的话,为什么不用访问修饰符呢?

  回复  引用  查看    
#24楼2009-10-30 10:16 | Anders Liu      
这……很有趣。:D
  回复  引用  查看    
#25楼2009-10-30 10:16 | 妖居      
这个如果以前做过控件开发,特别是WinForm下的控件开发应该会知道的。类似的Attribute还有DefaultValue、Category、Editor什么的。这种隐藏成员的方法.NET本身就在自己的BCL里面使用过。如果打开Object Browser的看到有个Member是斜体而且是灰色的,说明这个方法被微软隐藏了,可能是一些内部使用的方法但是又必须暴露出来。比如DataGridView里面有个HitTest方法(好像是这个名字)就是这样的。

不过小涛涛好像有点标题党了,呵呵。别介意哈。但是真的可以么?我自己试了试但是仍旧出现了Object的那些成员……

    [EditorBrowsable(EditorBrowsableState.Never)]
    public interface IAnyObject
    {
        [EditorBrowsable(EditorBrowsableState.Never)]
        bool Equals(object obj);

        [EditorBrowsable(EditorBrowsableState.Never)]
        int GetHashCode();

        [EditorBrowsable(EditorBrowsableState.Never)]
        Type GetType();

        [EditorBrowsable(EditorBrowsableState.Never)]
        string ToString();
    }

    public interface IObject : IAnyObject
    {
        void About();
    }

    public class AnyObject : IObject
    {
        #region IObject Members

        public void About()
        {
            throw new NotImplementedException();
        }

        #endregion
    }

    public class Main
    {
        public void Do()
        {
            IObject obj = new AnyObject();
        }
    }



  回复  引用  查看    
#26楼2009-10-30 10:20 | Magic R      
@飞林沙
在IDE提示里隐藏和用访问修饰符是两码事 区别太大了

  回复  引用  查看    
#28楼2009-10-30 10:21 | Ivony...      
引用飞林沙:
@GWPBrian

只是举一个例子,呵呵,不过具体什么用说实话我真没想到.... 如果想隐藏的话,为什么不用访问修饰符呢?



有时候访问修饰符是不能更改的,例如继承的成员。。。

  回复  引用  查看    
#29楼[楼主]2009-10-30 10:27 | Anytao      
@妖居
哈哈,那是你没有仔细看文章,里面有个“注意”的。

呵呵。

  回复  引用  查看    
#30楼2009-10-30 10:28 | AlexLiu      
时间对于别出心裁的小花样是最无情的
  回复  引用  查看    
#31楼2009-10-30 10:31 | Ivony...      
引用Anytao:
@妖居
哈哈,那是你没有仔细看文章,里面有个“注意”的。

呵呵。



我明白了,他在同一程序集。。。。

  回复  引用  查看    
#32楼2009-10-30 10:32 | 妖居      
@Ivony...
@Anytao
哈哈哈,刚刚看到。一般我是看到 参考资料 出现的时候就不看了,因为基本就是废话了。没想到小涛涛还在这篇文章中考验了读者是不是“粗线条”。呵呵,哥们儿这次是有点“粗”了。不过建议把那个 注意 变成粗体吧,否则可能会有不少同志要骂娘了。

  回复  引用  查看    
#33楼2009-10-30 11:22 | Jeffrey Zhao      
话说我来挑刺了,嘿嘿。
好像这个内容不属于“你必须知道的.NET”啊……

  回复  引用  查看    
#34楼[楼主]2009-10-30 11:44 | Anytao      
引用Jeffrey Zhao:
话说我来挑刺了,嘿嘿。
好像这个内容不属于“你必须知道的.NET”啊……


呵呵,明白明白。好像放在【开发故事】里,更好。

  回复  引用  查看    
#35楼2009-10-30 11:51 | 啊不才      
呵呵,厉害啊,O(∩_∩)O~
由衷的佩服~~!!

  回复  引用  查看    
#36楼2009-10-30 12:35 | From Ocean      
@涛哥
个人有个疑点想请教下
[EditorBrowsable(EditorBrowsableState.Never)]
    public interface IAnyObject
    {
        [EditorBrowsable(EditorBrowsableState.Never)]
        bool Equals(object obj);

        [EditorBrowsable(EditorBrowsableState.Never)]
        int GetHashCode();

        [EditorBrowsable(EditorBrowsableState.Never)]
        Type GetType();

        [EditorBrowsable(EditorBrowsableState.Never)]
        string ToString();
    }


这段代码为什么连interface前都要never下?现在我没有具体尝试,但是仍然想问为什么interface其下的属性和方法没有继承这个属性设定而非要重新指定了?
会不会以下代码和上述代码等效了?
[EditorBrowsable(EditorBrowsableState.Never)]
    public interface IAnyObject
    {
        bool Equals(object obj);
        int GetHashCode();
        Type GetType();
        string ToString();
    }

  回复  引用  查看    
#37楼2009-10-30 12:43 | 飞林沙      
@Magic R
引用Magic R:
@飞林沙
在IDE提示里隐藏和用访问修饰符是两码事 区别太大了


举个例子,有什么是用隐藏能做到,但是访问修饰符做不到的呢?

  回复  引用  查看    
#38楼2009-10-30 12:44 | 飞林沙      
@Ivony...
引用Ivony...:
引用飞林沙:
@GWPBrian

只是举一个例子,呵呵,不过具体什么用说实话我真没想到.... 如果想隐藏的话,为什么不用访问修饰符呢?



有时候访问修饰符是不能更改的,例如继承的成员。。。


什么意思呢?没懂?举个例子吧

  回复  引用  查看    
#39楼2009-10-30 12:59 | EricZhang(T2噬菌体)      
有趣,嘿嘿
  回复  引用  查看    
#40楼2009-10-30 13:10 | Ivony...      
引用Jeffrey Zhao:
话说我来挑刺了,嘿嘿。
好像这个内容不属于“你必须知道的.NET”啊……



嗯,改一下就行了:

你没必要知道的.NET

保证比现在这个标题更火爆。。。。。

  回复  引用  查看    
#41楼2009-10-30 13:14 | 李阳      
哈哈,不错~~~楼主扣的很细啊~~
  回复  引用  查看    
#42楼2009-10-30 13:43 | Jeffrey Zhao      
@Ivony...
其实我的想法和你差不多,嘿嘿。

  回复  引用  查看    
#44楼2009-10-30 15:11 | 凯锐      
怎麼我就調不出來呢?注意那段我也看到了呀,特意分了兩個專案,編譯成兩個程序集。一個專案中有代碼:
//這個IObject文件中的
namespace IAnyObject
{
    [EditorBrowsable(EditorBrowsableState.Never)]
    public interface IObject
    {
        [EditorBrowsable(EditorBrowsableState.Never)]
        bool Equals(object obj);

        [EditorBrowsable(EditorBrowsableState.Never)]
        int GetHashCode();

        [EditorBrowsable(EditorBrowsableState.Never)]
        Type GetType();

        [EditorBrowsable(EditorBrowsableState.Never)]
        string ToString();
    }
}

//這是IAnyObject中的
namespace IAnyObject
{
    public interface IAnyObject:IObject
    {
        void About();
    }
}

//這是AnyObject中的
namespace IAnyObject
{
    //看到注意了,就將其移到另一個專案中,所以注釋掉
    //public class AnyObject:IAnyObject
    //{
    //    #region IAnyObject Members

    //    public void About()
    //    {
    //        throw new NotImplementedException();
    //    }

    //    #endregion
    //}
}





另一個專案中有代碼:
namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            IAnyObject.IAnyObject obj = new AnyObject();
        }
    }

    //從另一個專案剪切過來的。
    public class AnyObject :IAnyObject.IAnyObject 
    {
        #region IAnyObject Members

        public void About()
        {
            throw new NotImplementedException();
        }

        #endregion
    }
}



運行後,obj照樣可以看到所有的成員。我還有哪裡沒有注意到嗎?

  回复  引用  查看    
#45楼2009-10-30 18:46 | 峻祁连      
说实话开始的确吓了我一跳,以为是什么惊天发现或者惊天要案呢,原来是这。嗯,文笔不错,标题也不错。
  回复  引用  查看    
#46楼2009-10-30 19:42 | 周销军      
测试了下,果然。其实我们可以直接在类中重写object的那几个方法,然后加上这个[EditorBrowsable(EditorBrowsableState.Never)] 特性,结果也是一样的。
  回复  引用  查看    
#47楼[楼主]2009-10-30 19:52 | Anytao      
引用Jeffrey Zhao:厉害,这你是如何知道的亚?


呵呵,怎么知道的,好像是很久之前的事儿,前些天整理整理,忽然响起了,就放在了towrite list(和你的那个一样:-),就写了。

  回复  引用  查看    
#48楼[楼主]2009-10-30 19:52 | Anytao      
@不常在
谢谢

  回复  引用  查看    
#49楼[楼主]2009-10-30 19:53 | Anytao      
引用Ivony...:
引用Jeffrey Zhao:厉害,这你是如何知道的亚?



呃,其实很多控件(组件)开发者接触这些东西会比较多,老赵是不是不玩控件的?

话说我做控件的时候也注意到过这个特性,不过当时就是注意到了,知道有啥用了,没进一步挖出这样的应用。


呵呵,其实我也是偶然注意到的:-)

  回复  引用  查看    
#50楼[楼主]2009-10-30 19:54 | Anytao      
引用Jeffrey Zhao:
@Ivony...
呃……真不写控件的……


你是除了不写控件,其他都写吧

  回复  引用  查看    
#51楼[楼主]2009-10-30 19:56 | Anytao      
引用javascript:
@Ivony...
控件的不是EditorBrowsableAttribute,而是BrowsableAttribute,只管属性窗口,没管代码编辑器。


引用Ivony...:
引用javascript:
@Ivony...
控件的不是EditorBrowsableAttribute,而是BrowsableAttribute,只管属性窗口,没管代码编辑器。



研究Browsable的时候我就扫到了这个EditorBrowsable。。。。

我当时在找让某个属性在ASP.NET标签中消失的方法。。。。。

感觉这玩意儿也是给控件开发者玩的,否则谁会找到那里去。。。



我感觉,最大的应该还是进行某些Code控制时,虽然是不必要知道的,但是知道了或许对Code是个小新鲜,就像我习惯于IAnyObject一样。

  回复  引用  查看    
#52楼[楼主]2009-10-30 19:57 | Anytao      
@cnhzlt
嘿嘿。

  回复  引用  查看    
#53楼[楼主]2009-10-30 19:58 | Anytao      
引用颜昌钢:代码编辑器智能感知隐藏了,但是,如果知道方法名,直接写出来,还是可以编译通过的


文中已经交代了

  回复  引用  查看    
#54楼2009-10-30 20:21 | Ivony...      
其实应用场景应该还是不难找的,

例如你设计了一个只读流(ReadOnlyStream : Stream),那么用这个办法屏蔽掉这个类的Write等方法,就很不错。

但我想了想,这个其实也不限于用于组件。大体上如果你要屏蔽什么基类的功能,用这个方法就不错。。。

当然你也不要忘了override再throw new NotSupportedException();

  回复  引用  查看    
#55楼2009-10-30 23:40 | 凯锐      
半夜突然想起这件事,再次上来看看是怎么回事,评论是看到增加了,却没有人屑于告诉我什么原因,不服气,查msdn,终于弄明白了,于是将dlll复制出来,再引用就OK了,惭愧,太低级错误了。让各位方家见笑了......
  回复  引用  查看    
#56楼2009-10-31 09:07 | 鹤冲天      
学习了,我在扩展方法分组里一直想隐藏这些方法,未遂!
现在知道了。

  回复  引用  查看    
#57楼2009-10-31 11:14 | 杨同学      
嗯,我还以为你可以像ruby 那样给类添加/删除 成员方法呢
  回复  引用    
#58楼2009-11-02 08:51 | Hanyd[未注册用户]
提醒:此种情况对VS自带的智能提示可用,对Resharper的无效。
  回复  引用  查看    
#59楼2009-11-03 22:43 | fisea      
像winform中的CheckBox控件的DataSource属性就点不出来了。
  回复  引用  查看    
#60楼2010-01-01 01:53 | JesseQu      
这种机制在COM时代就已经有了,在IDL文件中定义接口时,就可以为接口的成员指定类似的属性了。这个机制为既成产品形态的组件和操作它的工具之间规定了一个推荐的交互习惯,对组件本身不构成任何影响。上面“既成产品形态的组件”这个晦涩的表达,可以解释Anytao写在注意事项中的条件或约束的原因。
  回复  引用  查看    
#61楼[楼主]2010-01-01 16:29 | Anytao      
引用JesseQu:这种机制在COM时代就已经有了,在IDL文件中定义接口时,就可以为接口的成员指定类似的属性了。这个机制为既成产品形态的组件和操作它的工具之间规定了一个推荐的交互习惯,对组件本身不构成任何影响。上面“既成产品形态的组件”这个晦涩的表达,可以解释Anytao写在注意事项中的条件或约束的原因。


嗯,这样解释就再恰当不过了。了解历史很关键,以后给我多讲讲不知道的历史。

  回复  引用  查看    
#62楼[楼主]2010-01-01 16:31 | Anytao      
@Ivony...
引用Ivony...:
其实应用场景应该还是不难找的,

例如你设计了一个只读流(ReadOnlyStream : Stream),那么用这个办法屏蔽掉这个类的Write等方法,就很不错。

但我想了想,这个其实也不限于用于组件。大体上如果你要屏蔽什么基类的功能,用这个方法就不错。。。

当然你也不要忘了override再throw new NotSupportedException();



嗯,我也同意这样的用意和场合。

  回复  引用  查看    
#63楼[楼主]2010-01-01 16:31 | Anytao      
@凯锐
呵呵,小伙好有精力啊。

  回复  引用  查看    
#64楼[楼主]2010-01-01 16:32 | Anytao      
@鹤冲天
嘿嘿。不错吧。

  回复  引用  查看    
#65楼[楼主]2010-01-01 16:37 | Anytao      
@杨同学
两回事儿:-)

  回复  引用  查看    
#66楼[楼主]2010-01-01 16:37 | Anytao      
@Hanyd
您说的没错。

  回复  引用  查看    
#67楼[楼主]2010-01-01 16:38 | Anytao      
@fisea
你可以查明具体的原因。