前言

CSharp的特性(Attribute)是比较难以理解的技术,写代码时通常都要求写注释,为了是让其他程序猿快速理解代码含义,但是注释是写给'人'看的,突发奇想下:能不能写出给C#编译器看的注释,比如在某些代码段上打上标记,让编译器看到标记后,做出不同的运行效果?其实…这就是特性。

1.Serializable特性分析

为什么Serializable特性作为小节1讲解呢?因为它是比较常见的特性,在网络对象进行传输时和数据库进行对象保存时,使用序列化特性后的类、结构体、枚举等等都可实现序列化操作的,SerializableAttribute仅是标记而已,它并不执行序列化动作。这样为何在C#中必须要使用它呢?而其他语言好像没有C#这种技术,接下来展示序列化的代码:

using System;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;namespace TestPro
{
    [Serializable]public class Person{public int Age { get; set; }public int Sex { get; set; }public string Name { get; set; }}class Program{static void Main(string[] args){Person person = new Person();person.Age = 18;person.Sex = 0;person.Name = "李洛克";IFormatter formatter = new BinaryFormatter();Stream stream = new FileStream("PersonFile.bin", FileMode.Create,FileAccess.Write, FileShare.None);formatter.Serialize(stream, person);stream.Close();}}
}

运行生成.dll和.exe以后,通过ildasm查看il代码分析下原因,以下截图就是Person类的。

只是多了serializable指令,而且比起其他特性,它的构造函数都没有执行({}红色区域是正常特性的构造函数执行位置),从il代码看不出什么情况,只能从功能去猜想序列化实现的原理,通常来说序列化某个自定义类时,都要程序猿去实现具体的序列化方法(比如C、Delphi等等低级语言),而C#使用formatter.Serialize(stream, person)即可,这是什么神仙接口呢?(没有具体告诉接口类里有那些属性、变量),但使用它可完成基本的序列化动作,其实C#是通过反射这种技术去完成序列化接口的,了解反射原理的程序猿可自定义实现通用的序列化接口,反射打个比方就是文件夹下查找某个文件,使用序列化特性可以提高反射性能(查找对应类和获取到它的属性、变量性能),下面给出简单示意图。

使用序列化特性标记以后可提高性能,不用遍历程序集所有类、结构体,所以使用C#接口进行序列化时需要使用它,不然就自定义序列化接口(比如Person1使用Person1Serialize,Person2使用Person2Serialize)。如果对序列化方式不满意,但不想自定义序列化类,希望通过C#接口实现序列化也是有办法的,Person继承ISerializable,实现GetObjectData即可,比如序列化时给名字添加前缀或不序列化名字,代码实现如下。

   [Serializable]public class Person : ISerializable{public int Age { get; set; }public int Sex { get; set; }public string Name { get; set; }public void GetObjectData(SerializationInfo info, StreamingContext context){info.AddValue("Age", Age);info.AddValue("Sex", Sex);info.AddValue("Name","火影忍者" + Name);}}

2.CSharp预定义特性

小节2在网上可以普遍查询到的资料,这里简单说明下情况,.Net框架提供三种预定义特性:

  • AttributeUsage
  • Conditional
  • Obsolete

预定义特性 AttributeUsage 描述了如何使用自定义特性类。它规定了特性可应用到的项目的类型。规定该特性的语法如下:

   [AttributeUsage(validon,//AttributeTargets.Class...
       AllowMultiple=allowmultiple,//该特性是否多用的
       Inherited=inherited//该特性是否继承的
    )]

Conditional预定义特性标记了条件方法,其方法是否被执行依赖指定的预处理标识符是否被定义。具体代码如下:

#define DEBUG
using System;
using System.Diagnostics;
public class Debug
{
    [Conditional("DEBUG")]public static void Log(string msg){Console.WriteLine(msg);}    [Conditional("DEBUG")]public static void LogWarning(string msg){Console.WriteLine("w:" + msg);}    [Conditional("DEBUG")]public static void LogError(string msg){Console.WriteLine("e:" + msg);}
}
class TestPro
{public static void Main(){Debug.Log("In Main function.");Console.ReadKey();}
}

Obsolete预定义特性标记了不应被使用的程序实体。它可以让您通知编译器丢弃某个特定的目标元素。具体代码如下:

    public class Math{
        [Obsolete("Don't use Cal, use gCal instead", true)]public static void Cal(){}public static void gCal(){}}

3.(AttributeUsage)自定义特性使用

开发经常遇到的情况,就是结构体、类需要稍微调整下,但不想改动过大,而且改动逻辑是偏向行为方面的改变,比如消息协议类之前都是在单个服务器上运行的,经过实战以后发现服务器压力过大了,公司领导准备让程序猿优化服务器性能,首先想到的就是分布式服务器设计思路,把服务器功能分开后部署到不同服务器机器上(处理Http请求的服务器、数据库操作的服务器、网关服务器、处理游戏战斗模块服务器),这样可以很大程度减轻服务器的压力(把拆分出的服务器还是部署到一个机器上,就和之前没有区别,可能还会增加本地服务器之间微小的通信消耗),所以需要大量重构代码,这时可使用自定义特性的奇淫技巧来解决这方面问题,修改过的伪代码如下:

using System;
namespace TestPro
{public enum AppType{Gate,Realm,Http,DB}    [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = false)]public class MessageHandlerAttribute : Attribute{public AppType appType { get; }public Type selfType { get; }public MessageHandlerAttribute(){}public MessageHandlerAttribute(AppType appType){this.appType = appType;this.selfType = this.GetType();}}    [MessageHandler(AppType.Gate)]public class CG_LoginMessageHandler{public void RunTask(){Console.WriteLine("登陆网关服务器");}}    [MessageHandler(AppType.DB)]public class CD_RegisterMessageHandler{public void RunTask(){Console.WriteLine("注册数据库服务器");}}class Program{static void Main(string[] args){CD_RegisterMessageHandler registerMessageHandler = new CD_RegisterMessageHandler();var messageAttr = (MessageHandlerAttribute)Attribute.GetCustomAttribute(registerMessageHandler.GetType(), typeof(MessageHandlerAttribute));Console.WriteLine(messageAttr.appType);Console.WriteLine(messageAttr.selfType);}}
}

可能稍微修改代码就适合以上需求,正常来说Main函数里应该有个死循环,然后取用消息队列里的消息句柄类,通过特性附加的信息进行不同的处理(比如把消息分拨都其他服务器),这里只获取、打印出附加的特性信息,概念图应该如下所示:

可能分布式服务器的概念图是这样的,如果不符合逻辑的话或者不够严谨的话(随便画的),希望各位不要太过较真,可以理解大概意思即可。

4.总结

常用的内建特性表格:

特性 作用
JsonProperty JsonConvert.SerializeObject指定json格式的键值名称
Serializable 可序列化
NonSerialized 不可序列化,可在类内部变量使用,表面序列化时过滤掉它
DLLImport 非托管代码实现的
WebMethod 被作为web服务器对外暴露的方法
Required 必须存在的字段
MaxLength(100) 限制字符串、数组长度
DebuggerStepThrough 在代码打断点调试过程中,不进入该方法,加在不可能有错误的地方,方便调试
  • Attribute是什么?
    Attribute是一种可由用户自有定义的修饰符(Modifier),可以用来修饰各种需要被修饰的目标。可以对类、以及C#程序集中的成员进行进一步的描述。简单地说,Attribute就是一种“附着物”,就像牡蛎吸附在船底或礁石上一样。 这些附着物的作用是为它们附着体追加上额外的信息(这些信息保存在附着物的体内),通过Ildasm可以发现特性通常会被附带构造,Attribute是程序代码一部分,它不会被编译器丢弃,而且还会被编译器编译进程序集(Assembly)的元数据里(Metadata)里。在程序运行时,可以随时从元数据(.NET的元数据是指程序集中的命名空间、类、方法、属性等信息,这些信息是可以通过Reflection读取出来的)中获取出这些附加信息,并可以决策程序的运行效果。

  • Attribute与注释的区别
    注释是对程序源代码的说明,主要目的是给人看的,在程序被编译的时候会被编译器所丢弃,因此它丝毫不会影响到程序的执行。Attribute是给编译器看的,CSharp内建的特性可以达到很多有趣的效果,比如跳过调式、提示函数过期、编译开关效果等,自定义的特性也可以自行决定附加信息的用处。

CSharp特性详解相关推荐

  1. 还在用JDK6的同学,来看看JDK13新特性详解吧

    点击上方"搜云库技术团队"关注,选择"设为星标" 回复"面试题"或"1024"获取 4T 学习资料 在 JDK 版本的世 ...

  2. java11 新特性 详解

    为什么80%的码农都做不了架构师?>>>    引言: 点击-->java10 新特性 详解 点击-->java9 新特性 详解 点击-->java8 新特性 详解 ...

  3. 4.6 W 字总结!Java 11—Java 17特性详解

    作者 | 民工哥技术之路 来源 | https://mp.weixin.qq.com/s/SVleHYFQeePNT7q67UoL4Q Java 11 特性详解 基于嵌套的访问控制 与 Java 语言 ...

  4. 【干货】PMcaff干货课程学习精彩分享:Apple Watch 技术特性详解

    昨天PMcaff给大家推荐了Apple Watch的发布会,好多小伙伴们在后台留言,所以PMcaff小咖今天给大家找来一篇干货,看完感觉还不错,在这里分享给大家. 作为苹果主推的智能穿戴产品,Appl ...

  5. 《Android群英传》读书笔记 (5) 第十一章 搭建云端服务器 + 第十二章 Android 5.X新特性详解 + 第十三章 Android实例提高...

    第十一章 搭建云端服务器 该章主要介绍了移动后端服务的概念以及Bmob的使用,比较简单,所以略过不总结. 第十三章 Android实例提高 该章主要介绍了拼图游戏和2048的小项目实例,主要是代码,所 ...

  6. C#各个版本中的新增特性详解

    序言 自从2000年初期发布以来,c#编程语言不断的得到改进,使我们能够更加清晰的编写代码,也更加容易维护我们的代码,增强的功能已经从1.0搞到啦7.0甚至7.1,每一次改过都伴随着.NET Fram ...

  7. Java基础学习总结(33)——Java8 十大新特性详解

    Java8 十大新特性详解 本教程将Java8的新特新逐一列出,并将使用简单的代码示例来指导你如何使用默认接口方法,lambda表达式,方法引用以及多重Annotation,之后你将会学到最新的API ...

  8. Java9 新特性 详解

    目录 Java9 新特性 详解 1.Java9新特性之---目录结构 2.Java9新特性之---JShell工具 3.Java9新特性之---模块化 4.Java9新特性之---多版本兼容Jar包 ...

  9. 好程序员技术分析JavaScript闭包特性详解

    为什么80%的码农都做不了架构师?>>>    好程序员技术分析JavaScript闭包特性详解,今天来总结一下js闭包的那些事,以及遇到的坑和解决方法,希望对你有所帮助. 是的,没 ...

最新文章

  1. 电力系统稳定与控制_基于数据驱动的电力系统稳定性分析
  2. php 做的网页 排版错误,discuz 帖子排版显示出错
  3. Facebook最新Libra币开发指南---接口服务器开发2
  4. linux 批量部署 pdf,Linux服务之批量部署篇
  5. (翻译)Google Guava Cache
  6. maya如何导出ue4_ue4 maya max导入导出问题
  7. 谈谈遵守公司作战纪律
  8. Ubuntu下The program 'python' can be found in the following packages:
  9. 编码基本功:相似函数参数顺序要一致
  10. MATLAB常用画图函数
  11. [UE4][Material] Spline样条网格材质消失问题记录
  12. 纯技术上来说,《看门狗》里的各种骇客技术有可能实现吗?
  13. php数据库ip,php读取纯真ip数据库使用示例
  14. 【微信小程序】史上最全的《Java面试题及解析》,理论+实战双管齐下!
  15. python实现英文新闻摘要自动提取_利用Python实现摘要自动提取,完美瘦身只需一行代码...
  16. 对《GitHub服务中断24小时11分钟事故分析报告》的分析
  17. 高三班主任写给学生的一封信
  18. 高效能人士的七个习惯及亚马逊十四条领导力准则
  19. html-loader、css-loader、style-loader简单描述
  20. 极验滑块验证码破解最新版

热门文章

  1. Ming-Hsuan Yang: Publications
  2. 《与巴菲特共进午餐时,我顿悟到的5个真理》精髓:通过投资的5个真理,教你成为一名真正的价值投资者。
  3. O365批量重置用户密码
  4. 介绍 EVM 等效性
  5. i春秋CTF Hash
  6. 要关闭python解释器可使用函数或者快捷键_【填空题】要关闭Python解释器,可使用函数【1】或者快捷键【2】。...
  7. 纸牌屋第一季(2)--part1
  8. 桥梁计算机辅助设计教科书,桥梁工程基础课程教学大纲详解.doc
  9. 使用Python和OpenCV实现身份证识别
  10. java读取excel(java读取excel表格存入数据库)