热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

开发笔记:20181114_特性

本文由编程笔记#小编为大家整理,主要介绍了20181114_特性相关的知识,希望对你有一定的参考价值。一.  特性:比如下图中的Obsole
本文由编程笔记#小编为大家整理,主要介绍了20181114_特性相关的知识,希望对你有一定的参考价值。


一.   特性:

比如下图中的Obsolete是特性, CustomAttribute是特性(自定义的特性), Serializable也是特性

技术分享图片

二.    特性的作用:

a)         特性的核心作用:补充; 就像反射的核心作用一样: 动态

b)         影响编译器的运行; [Obsolete("请不要使用这个了,请使用什么来代替", true)]如果是true则引用的时候, 编译器会报错

c)         影响程序的运行; 比如[Serializable]表示某个类是否可以序列化和反序列化

      对于上图中标记的特性的说明:

      [Obsolete("请不要使用这个了,请使用什么来代替", true)]//影响编译器的运行 ; 这个特性一般用在api升级的时候; 比如1.0中有一个函数叫getProductinfo(),

      那么2.0中对此函数进行了升级getProductinfo(string shopId); 那么可以在API中对1.0中的getProductinfo()函数上面添加此特性; 在调用的时候就会有这样的提示

           [Serializable]//可以序列化和反序列化  可以影响程序的运行

d)         特性就是一个类, 继承自attribute, 一般以Attribute结尾, 在标记的时候和声明时候都可以省略掉, 因为特性本身就是一个类, 那么它当然可以包含属性/字段/方法/委托/事件

e)         自定义的特性一般以Attribute结尾,声明时(使用时) 可以省略掉Attribute

f)          当使用特性进行修饰元素的时候, 默认只能修饰一次, 如果需要多次修饰的话, 要在定义此特性的类上增加 

      [AttributeUsage(AttributeTargets.All, AllowMultiple = true)]       

      //AllowMultiple = true默认值为false; 通常也不推荐修改为true, 一般使用默认值即可

 技术分享图片

g)        AttributeUsage是一个专门用来修饰特性的一个特性类, 它用来描述, 某个特性类, 可以用在什么地方(类上-方法上-属性上)/是否可以叠加使用/是否可以被继承等. . .

h)     [AttributeUsage(AttributeTargets.Class,  AllowMultiple = true)]

    AttributeTargets 是一个枚举; 指定class表示只能修饰类  ; 指定Method则表示修饰方法

    AttributeTargets.All|AttributeTargets.Method

    Inherited = true表示此特性是否可以被继承

 技术分享图片

i)  特性可以添加到方法上/类上/属性上/返回值上


[CustomAttribute] //属性添加特性
public int Id { get; set; }
[Custom()] //给方法添加特性
[return: Custom()] //给返回值添加一个特性; 很少见
public string Answer([Custom]string name) //给参数添加特性
{
return $"This is {name}";
}

j) 特性, 本身是没用的 , 任何一个生效的特性,都是因为其它地方的主动使用; 没有破坏类型封装的前提下,可以加点额外的信息和行为, 但是这是有前提的, 也就是说必须通过反射才行, 因为给一个元素上特性添加后,编译器会在元素内部标记元数据, 可以通过IL(中间语言)查看, 但是元数据我们是没办法直接使用的, 只有通过反射来调用 ; 如果不用调用, 特性相当于就没有用

三.   创建自定义的特性类, 代码如下:


///


/// 检查数字是否在指定范围内的特性, 这个特性在使用的时候, 需要传递两个参数, 且都是long类型的
///

public class LongAttribute : Attribute //自定义特性类, 必须继承Attribute
{
private long _Min = 0;
private long _Max = 0;
public LongAttribute(long min, long max)
{
this._Min = min;
this._Max = max;
}
public bool Validate(object value)//" "
{
if (value != null && !string.IsNullOrWhiteSpace(value.ToString()))
{
//检查value是不是long类型, 如果是, 则复制给lResult;
if (long.TryParse(value.ToString(), out long lResult))
{
if (lResult > this._Min && lResult {
return true;
}
}
}
return false;
}
}

四.   特性基本说明:

a)   简单介绍, Custom是在上面自定义的那个特性类:

  [Custom]

     [Custom()]//调用空的构造函数, 以上两种写法效果一样

     //这种写法就等于在实例化一个类

     [Custom(123), Custom(123, Description = "1234")]

    //这里要注意, 如果是构造函数的参数, 可以直接传递, 如果是字段, 则必须使用 字段名=值 的格式

 [Custom(123, Description = "1234", Remark = "2345")]//方法不行

 

五.   使用反射将枚举值转变成字符, 要达到的效果如下图; 

 技术分享图片

a)         定义特性类RemarkAttribute, 代码如下:


///


/// 自定义特性类; 特性类必须继承 Attribute
///

public class RemarkAttribute : Attribute //特性的类的后缀Attribute, 是可以省略的; 但是只有在使用的时候可以省略
{
private string _Remark = null;
public RemarkAttribute(string remark)
{
this._Remark = remark;
}
public string GetRemark()
{
return this._Remark;
}
}

b) 对Enum类型进行反射取值, 直接使用对枚举扩展的方法来操作, 定义枚举扩展类RemarkExtension:


///


/// 查找特性的类, 这个类仅仅对枚举类型进行了扩展
///

public static class RemarkExtension
{
///
/// 由于添加了this, 那么这是一个扩展方法, 任何枚举都可以调用这个方法
///

///
///
public static string GetRemark(this Enum value) //对枚举进行扩展
{
//根据传递的值得到一个枚举类型
Type type = value.GetType();
//找出对应的字段; 枚举中定义的都是字段, 而不是属性
FieldInfo field = type.GetField(value.ToString());
//判断该字段上是不是打有 Remark特性
if (field.IsDefined(typeof(RemarkAttribute), true))
{
RemarkAttribute attribute = (RemarkAttribute)field.GetCustomAttribute(typeof(RemarkAttribute), true);
return attribute.GetRemark();
}
else
{
return value.ToString();
}
}
}

c) UserState的枚举类代码


///


/// 用户状态; 绑定界面属性; 在webForm时代, 最常见的就是 用户名: textbox 密码: textbox
/// 那么通过特性, 用户名 这样的字符串都可以是动态的
///

public enum UserState
{
///
/// 正常
///

[Remark("正常")] //使用特性; 特性类在下面
Normal = 0,//左边是字段名称(Normal),右边是数据库值(0),哪里放描述?也就是说要在界面上展示的 正常 字符
///
/// 冻结
///

[Remark("冻结")]
Frozen = 1,
///
/// 删除
///

//[Remark("删除")]
Deleted = 2
}

 d)  调用方法:


#region 通过特性为字段/属性/成员添加一些信息
UserState userState = UserState.Normal;
if (userState == UserState.Normal)
{
Console.WriteLine("正常状态"); //界面绑定一个中文
}
else if (userState == UserState.Frozen)
{ }
else
{ }
//GetRemark()方法是个扩展了Enum的方法; 任何定义个枚举都可以调用
Console.WriteLine(userState.GetRemark());
//常规的调用方法
Console.WriteLine(RemarkExtension.GetRemark(userState));

#endregion

 六. 通过扩展object类, 检查属性的合法性, 属性的值是否在指定范围之内 

 a) 自定义的抽象特性类:


///


/// 抽象类, 每一个需要约束的方法都继承此类
///

public abstract class AbstractValidateAttribute : Attribute
{
public abstract bool Validate(object value);
}

 b)  字符长度的校验类, 继承抽象类 AbstractValidateAttribute:


///


/// 只能让他修饰属性和字段; 检查字符串长度的特性
///

[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
public class LengAttribute : AbstractValidateAttribute
{
private int _Min = 0;
private int _Max = 0;
///
/// 特性类的构造函数
///

///
///
public LengAttribute(int min, int max)
{
this._Min = min;
this._Max = max;
}
public override bool Validate(object value)//" "
{
//return value != null && !string.IsNullOrWhiteSpace(value.ToString()) && value.ToString().Length > _Min && value.ToString().Length <_Max;
if (value != null && !string.IsNullOrWhiteSpace(value.ToString()))
{
int length = value.ToString().Length;
if (length > this._Min && length {
return true;
}
}
return false;
}
}

 c) 检查数字是否在指定范围内, 继承抽象类AbstractValidateAttribute:


///


/// 检查数字是否在指定范围内的特性, 这个特性在使用的时候, 需要传递两个参数, 且都是long类型的
///

[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
public class LongAttribute : AbstractValidateAttribute
{
private long _Min = 0;
private long _Max = 0;
public LongAttribute(long min, long max)
{
this._Min = min;
this._Max = max;
}
public override bool Validate(object value)//" "
{
if (value != null && !string.IsNullOrWhiteSpace(value.ToString()))
{
//检查value是不是long类型, 如果是, 则复制给lResult;
if (long.TryParse(value.ToString(), out long lResult))
{
if (lResult > this._Min && lResult {
return true;
}
}
}
return false;
}
}

d) 扩展object类, 注意由于是扩展的object类, 那么所有的类型都将具有这个方法:


///


/// 验证扩展类
///

public static class ValidateExtension
{
///
/// 验证扩展
///

///
///
public static bool Validate(this object oObject)
{
Type type = oObject.GetType();
foreach (var prop in type.GetProperties())
{
//检查prop上是不是有这个 抽象 的特性, 这个抽象当前派生了两个类, 如果有需要则可以继续进行派生, 但是此类就无需再修改, 当然如果想要报错更清晰一点, 可以修改此类
if (prop.IsDefined(typeof(AbstractValidateAttribute), true))
{
object[] attributeArray = prop.GetCustomAttributes(typeof(AbstractValidateAttribute), true);
foreach (AbstractValidateAttribute attribute in attributeArray)
{
if (!attribute.Validate(prop.GetValue(oObject)))
{
return false;
}
}
}

}
return true;
}
}

e) 需要校验属性的类, 这里使用student类进行模拟校验:  


public class Student
{
///


/// 相当于调用了Leng这个特性类的构造函数
///

[Leng(5, 10)]
public string Name { get; set; }
[Extension.Leng(20, 50)]
public string Accont { get; set; }
///
/// 10001~999999999999
///

[Long(10001, 999999999999)]
public long QQ { get; set; }
}

f)    调用方式; 还是那一句→所有的特性都要主动去调用:

      由于特性是基于object扩展的, 所以任何类都可以主动去使用


Student student = new Student();

student.Name = "孙悟空";
student.QQ = 123456;
student.AccOnt= "23434234243323";
student.Validate();

  

 


推荐阅读
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • 本文介绍了一个在线急等问题解决方法,即如何统计数据库中某个字段下的所有数据,并将结果显示在文本框里。作者提到了自己是一个菜鸟,希望能够得到帮助。作者使用的是ACCESS数据库,并且给出了一个例子,希望得到的结果是560。作者还提到自己已经尝试了使用"select sum(字段2) from 表名"的语句,得到的结果是650,但不知道如何得到560。希望能够得到解决方案。 ... [详细]
  • 前景:当UI一个查询条件为多项选择,或录入多个条件的时候,比如查询所有名称里面包含以下动态条件,需要模糊查询里面每一项时比如是这样一个数组条件:newstring[]{兴业银行, ... [详细]
  • 本文详细介绍了如何使用MySQL来显示SQL语句的执行时间,并通过MySQL Query Profiler获取CPU和内存使用量以及系统锁和表锁的时间。同时介绍了效能分析的三种方法:瓶颈分析、工作负载分析和基于比率的分析。 ... [详细]
  • 本文由编程笔记#小编为大家整理,主要介绍了logistic回归(线性和非线性)相关的知识,包括线性logistic回归的代码和数据集的分布情况。希望对你有一定的参考价值。 ... [详细]
  • 生成式对抗网络模型综述摘要生成式对抗网络模型(GAN)是基于深度学习的一种强大的生成模型,可以应用于计算机视觉、自然语言处理、半监督学习等重要领域。生成式对抗网络 ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • Linux重启网络命令实例及关机和重启示例教程
    本文介绍了Linux系统中重启网络命令的实例,以及使用不同方式关机和重启系统的示例教程。包括使用图形界面和控制台访问系统的方法,以及使用shutdown命令进行系统关机和重启的句法和用法。 ... [详细]
  • javascript  – 概述在Firefox上无法正常工作
    我试图提出一些自定义大纲,以达到一些Web可访问性建议.但我不能用Firefox制作.这就是它在Chrome上的外观:而那个图标实际上是一个锚点.在Firefox上,它只概述了整个 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • http:my.oschina.netleejun2005blog136820刚看到群里又有同学在说HTTP协议下的Get请求参数长度是有大小限制的,最大不能超过XX ... [详细]
  • 本文介绍了Web学习历程记录中关于Tomcat的基本概念和配置。首先解释了Web静态Web资源和动态Web资源的概念,以及C/S架构和B/S架构的区别。然后介绍了常见的Web服务器,包括Weblogic、WebSphere和Tomcat。接着详细讲解了Tomcat的虚拟主机、web应用和虚拟路径映射的概念和配置过程。最后简要介绍了http协议的作用。本文内容详实,适合初学者了解Tomcat的基础知识。 ... [详细]
  • 在重复造轮子的情况下用ProxyServlet反向代理来减少工作量
    像不少公司内部不同团队都会自己研发自己工具产品,当各个产品逐渐成熟,到达了一定的发展瓶颈,同时每个产品都有着自己的入口,用户 ... [详细]
  • 闭包一直是Java社区中争论不断的话题,很多语言都支持闭包这个语言特性,闭包定义了一个依赖于外部环境的自由变量的函数,这个函数能够访问外部环境的变量。本文以JavaScript的一个闭包为例,介绍了闭包的定义和特性。 ... [详细]
  • Oracle优化新常态的五大禁止及其性能隐患
    本文介绍了Oracle优化新常态中的五大禁止措施,包括禁止外键、禁止视图、禁止触发器、禁止存储过程和禁止JOB,并分析了这些禁止措施可能带来的性能隐患。文章还讨论了这些禁止措施在C/S架构和B/S架构中的不同应用情况,并提出了解决方案。 ... [详细]
author-avatar
1500799277_a9483d_353
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有