使用Attribute的作用之一,就是在运行的时候,通过反射,获取一个类的一些额外的信息。那么既然这样的话,为什么不把这些信息已成员变量的方式存在类中呢。

解决方案 »

  1.   

    http://kb.cnblogs.com/page/87531/
      

  2.   

    因为反射的时候,成员变量除非是静态的,否则是无法得到其值的,但Attribute和具体实例无关,只要类型定义存在,就可以获得其值。
      

  3.   

    想让人编程自然不需要标记,因为你自己知道,而如果你想用机器自己编程那么自然需要弄个标记去告诉机器怎么办Attribute有元数据编程的影子,而元数据编程的一个理想化目标就是让代码自己组织代码。
      

  4.   

    晚上宵夜回来了,补充说一下把。呵呵,喝点酒,你就当我是酒醉胡说把,因为我下面要说滴会颠覆上面那几位的回答上面说Attribute似乎和静态,public相关,其实不是,反射的时候实际可以反射这个type的所有元数据。
    那么为啥会有这个玩意,其实你自己都已经回答了。
    Attribute只能用在反射上,也就是程序员在常规代码编写上根本用不到他,也就是他必须在代码运行期去“动态”查询元数据那么你的问题就可以解释了,为啥不把Attribute的东西,直接放在class里,答案就已经出来了,放在Attribute的是程序员在静态的设计期里是根本不需要使用的玩意,他都是运行期需要的一些“晚绑定”条件,他需要应用在一些由代码自己组织代码的运行期里面,比如早期的一些ORM,使用Attribute去映射字段和属性的关系,我们说如果是ORM,那么字段和属性的关系,其实是应用程序员不关心的玩意,那么谁关心他呢?是那些编写ORM框架的人才关心他,编写ORM的为啥关心他呢,因为编写ORM的说,我不希望和具体映射相关,我希望是个抽象,我希望是一个以一挡百的框架,我希望我的代码可以在运行期或编译期自己去生成组织代码。ok,这里答案基本就出来了,也就是你不希望浆糊程序员去关心,而希望一些框架类程序员去用代码生成的玩意,则使用Attribute,比如xml序列化,websevice的json序列化都使用了Attribute,因为大多数情况下俺们并不需要让浆糊程序员去关心具体的序列化过程,他们只需要俺规则申明就ok了,至于具体在运行期序列化的过程交给了框架程序员,而框架程序员的原则是抽象,是让代码自己生成代码,为了达到这种目的,所以俺们必须用Attribute标记一下,不然抽象的框架可认不出具体玩意在反过来说,不用Attribute可以不,其实可以。一个变通的方法就是EF里面“约定优于配置”,EF凭啥认定这玩意是key?EF说你可以不用Attribute去标记他,但是你必须按我的约定去定义name名称,只要你按我的规定命名了那么我的框架程序员们就知道,那个属性是key了,这样你就可以不用Attribute去标记他为key
      

  5.   

    Attribute基本可以用接口代替比如类上的Attribute,我也可以定义成空接口,还方便,直接用is就行了,不用反射
    比如类上带参数的Attribute,我也可以定义成接口,然后接口方法里返回参数值
    比如成员(属性字段event方法)上的Attribute,我也可以定义成类的接口、然后在接口方法里返回该类中哪些成员需要定义该Attribute
      

  6.   

    根本就不能用接口替代,比如Linq To Sql里面的各个数据库表的映射类,都有Attribute指明对应了是原来数据库中的哪个表名,哪个列名,这种情况怎么用成员变量来做,怎么用接口来做?这些附加信息完全不用在后面的使用上面,只是在创建sql语句时会用到,而且是脱离了实例的反射,不传递实例的情况下,根本就没有反射成员变量的可能性。
      

  7.   

    另外Attribute不仅仅可以用在类的定义上面,还可以用在字段上面,比如下面的写法,定义运行时解析的变量:
    [System.Runtime.CompilerServices.Dynamic]
    object data;
    它等同于
    dynamic data;
    dynamic关键字不是数据类型,只是C#的一个语法糖,最终表示形式是通过Attribute对object类型的修饰来实现的。运行时反射字段的Attribute,如果发现有System.Runtime.CompilerServices.Dynamic的Attribute,就特殊处理它。
      

  8.   


    我上边提到了成员的实现,比如下边这样。效率应该不比用Attribute差
    不过经你提醒,静态成员的Attribute确实不好通过接口做(但可以通过约定静态方法名做),效率也类似,都是用到一次反射调用
      

  9.   

    Attribute是绑定到元数据的,与实例没有任何关系
      

  10.   


    确实,接口不能规范静态方法,我考虑不周。只能靠约定。如果没有发明Attribute,完全可以约定:想实现类似功能的类增加一个static string GetFieldsWithAttribute(string AttributeName); 
      

  11.   

    你的比如,恰恰证明11楼的观点是正确的,
    从设计角度,这个用接口完全可以实现;其实5楼已经说的很形象了,
    因为Attribute的实现是嵌入代码封装的,倒更像是在瓶子上打钢印
      

  12.   

    如果仅仅是实现类似的功能,根本就不需要接口,直接定义一个统一的静态调用,像#14的代码一样,把所有需要的特性都手动写进去,比如:        public static class attribute
            {
                private static Dictionary<MemberInfo, Dictionary<Type, object>> members;
                public static attributeType Get<attributeType>(MemberInfo memberInfo) where attributeType : class
                {
                    Dictionary<Type, object> attributes;
                    if (members.TryGetValue(memberInfo, out attributes))
                    {
                        object value;
                        if (attributes.TryGetValue(typeof(attributeType), out value)) return (attributeType)value;
                    }
                    return null;
                }
                static attribute()
                {
                    //在这里把元数据与特性绑定
                }
            }
    但是问题是,为什么我们要用这么难以维护的实现这个功能呢?
      

  13.   

                /// <summary>
                /// 日志类型
                /// </summary>
                public enum type
                {
                    /// <summary>
                    /// 修改用户头像
                    /// </summary>
                    [logType(valuesLess = isValue.creator)]
                    reworkAvatar,
                    /// <summary>
                    /// 关注用户
                    /// </summary>
                    [logType(valuesLess = isValue.creator | isValue.user)]
                    focusUser,
                    /// <summary>
                    /// 创建话题
                    /// </summary>
                    [logType(valuesLess = isValue.creator | isValue.topic)]
                    createTopic,
                    /// <summary>
                    /// 关注话题
                    /// </summary>
                    [logType(valuesLess = isValue.creator | isValue.topic)]
                    focusTopic,
                    /// <summary>
                    /// 修改话题名称
                    /// </summary>
                    [logType(valuesLess = isValue.creator | isValue.topic)]
                    reworkTopicName,
                    /// <summary>
                    /// 修改话题描述
                    /// </summary>
                    [logType(valuesLess = isValue.creator | isValue.topic)]
                    reworkTopicDescription,
                    /// <summary>
                    /// 修改话题图片
                    /// </summary>
                    [logType(valuesLess = isValue.creator | isValue.topic)]
                    reworkTopicLogo,
                    /// <summary>
                    /// 修改话题经验
                    /// </summary>
                    [logType(valuesLess = isValue.creator | isValue.topic)]
                    reworkTopicExperience,
                    /// <summary>
                    /// 创建问题
                    /// </summary>
                    [logType(valuesLess = isValue.creator | isValue.question)]
                    createQuestion,
                    /// <summary>
                    /// 关注问题
                    /// </summary>
                    [logType(valuesLess = isValue.creator | isValue.question)]
                    focusQuestion,
                    /// <summary>
                    /// 同问问题
                    /// </summary>
                    [logType(valuesLess = isValue.creator | isValue.question)]
                    sameQuestion,
                    /// <summary>
                    /// 修改问题标题
                    /// </summary>
                    [logType(valuesLess = isValue.creator | isValue.question)]
                    reworkQuestionTitle,
                    /// <summary>
                    /// 修改问题描述
                    /// </summary>
                    [logType(valuesLess = isValue.creator | isValue.question)]
                    reworkQuestionDescription,
                    /// <summary>
                    /// 添加问题评论
                    /// </summary>
                    [logType(isValue = isValue.questionComment, valuesLess = isValue.creator | isValue.question)]
                    appendQuestionComment,
                    /// <summary>
                    /// 添加问题话题
                    /// </summary>
                    [logType(valuesLess = isValue.creator | isValue.question | isValue.topic)]
                    appendQuestionTopic,
    比如枚举的特性,手动实现得多麻烦。
      

  14.   

    换句话说,放到我们的生产方式当中,attribute的做法还不够漂亮,但是却和我们的做法很相似,
    区别是我们依赖文档描述,微软依赖代码描述
      

  15.   

    你这个观点我认可,很多技术手段都是围绕"代码即文档"展开的,比如TDD
    (其实说到底,C#也是文档+约定);
    但是我的想法刚好反过来,我的理由:
    1.设计最初就是从文档开始的
    2.围绕文档,
        可以有多重实现(在不同的PL,相同的业务逻辑不需要重复实现),
        多角度实现(既不是CodeFirst,也不是DBFist,而是它们都依赖文档,而不是相互依赖),
        多样性呈现(规划者视图,所有者视图,开发者视图)
    3.文档更加容易管理和测试
      

  16.   

    这里有个概念一定要纠正,Attribute不是瓶子上打的钢印,而是用来往瓶子上打的“钢印”本身。
      

  17.   

    1.设计最初就是从文档开始的
    这本身就是一个伪命题,文档只是项目管理的一种方式之一,看清楚只是“之一”
    另外一个,机器本身没法读懂非特定格式的文档,而Attribute可以认为是写给机器看的文档。
    什么是机器呢?目前各种使用了Attribute的架构或者处理方法可以认为是广义上“机器”,这其实设计到一个宏远的目标,就是程序的自我进化,不过这是理想中的事情啦。