使用Attribute的作用之一,就是在运行的时候,通过反射,获取一个类的一些额外的信息。那么既然这样的话,为什么不把这些信息已成员变量的方式存在类中呢。
解决方案 »
- 一个考勤班次问题,高手来帮我解决一下
- .net(C#) winform开发实现数据库报表以excel导出!!!求高手指点!!!
- 使用线程为什么比进程好?
- 关于 calendarextender (AJAX控件) 被其他控件挡住显示不了的问题
- 求助如何获取fckeditor 的文本内容
- 用sql server数据库建表时的问题
- dataGrid1.TableStyles.Count等于0
- C#treeview点击问题
- 调用C++接口错误问题
- 我刚装的.net,不知怎么搞的,不能新建项目,cpu跑到100%,各位仁兄,帮帮忙,我该怎么处理?
- 准备做一个在线考试系统,有几个问题请教各位。
- 。。关于WCF。。使用win服务做宿主。。局域网。使用TCP通信可以吧?
那么为啥会有这个玩意,其实你自己都已经回答了。
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
比如类上带参数的Attribute,我也可以定义成接口,然后接口方法里返回参数值
比如成员(属性字段event方法)上的Attribute,我也可以定义成类的接口、然后在接口方法里返回该类中哪些成员需要定义该Attribute
[System.Runtime.CompilerServices.Dynamic]
object data;
它等同于
dynamic data;
dynamic关键字不是数据类型,只是C#的一个语法糖,最终表示形式是通过Attribute对object类型的修饰来实现的。运行时反射字段的Attribute,如果发现有System.Runtime.CompilerServices.Dynamic的Attribute,就特殊处理它。
我上边提到了成员的实现,比如下边这样。效率应该不比用Attribute差
不过经你提醒,静态成员的Attribute确实不好通过接口做(但可以通过约定静态方法名做),效率也类似,都是用到一次反射调用
确实,接口不能规范静态方法,我考虑不周。只能靠约定。如果没有发明Attribute,完全可以约定:想实现类似功能的类增加一个static string GetFieldsWithAttribute(string AttributeName);
从设计角度,这个用接口完全可以实现;其实5楼已经说的很形象了,
因为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()
{
//在这里把元数据与特性绑定
}
}
但是问题是,为什么我们要用这么难以维护的实现这个功能呢?
/// 日志类型
/// </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,
比如枚举的特性,手动实现得多麻烦。
区别是我们依赖文档描述,微软依赖代码描述
(其实说到底,C#也是文档+约定);
但是我的想法刚好反过来,我的理由:
1.设计最初就是从文档开始的
2.围绕文档,
可以有多重实现(在不同的PL,相同的业务逻辑不需要重复实现),
多角度实现(既不是CodeFirst,也不是DBFist,而是它们都依赖文档,而不是相互依赖),
多样性呈现(规划者视图,所有者视图,开发者视图)
3.文档更加容易管理和测试
这本身就是一个伪命题,文档只是项目管理的一种方式之一,看清楚只是“之一”
另外一个,机器本身没法读懂非特定格式的文档,而Attribute可以认为是写给机器看的文档。
什么是机器呢?目前各种使用了Attribute的架构或者处理方法可以认为是广义上“机器”,这其实设计到一个宏远的目标,就是程序的自我进化,不过这是理想中的事情啦。