[AttributeUsage(AttributeTargets.Class|AttributeTargets.Method,AllowMultiple = true)]
AttributeTargets.Class|AttributeTargets.Method这两个东东进行位运算后的值是什么东西啊??个人觉得应该是用||才对啊。类或方法嘛。
位运算学得不好哪位大哥有这方面的书推荐吗。关于位运算的。还有学习递归类的书。。基础不牢啊
AttributeTargets.Class|AttributeTargets.Method这两个东东进行位运算后的值是什么东西啊??个人觉得应该是用||才对啊。类或方法嘛。
位运算学得不好哪位大哥有这方面的书推荐吗。关于位运算的。还有学习递归类的书。。基础不牢啊
枚举常量通常表示互斥的元素,一个变量的取值只能是其中一个元素。
使用位运算后,可以表示成几个枚举元素的组合。
[Flags]
public enum FlagEnum
{
A = 0x01,
B = 0x02,
C = 0x04,
D = 0x08
}
public class EnumTest
{
static void Main(string[] args)
{
FlagEnum f1 = FlagEnum.A | FlagEnum.C;
System.Console.WriteLine("f1 = " + f1);
}
}
输出:
f1 = A, C
AttributeTargets.Class|AttributeTargets.Method,
多个目标类型可同时进行“或”运算,参数必须是 AttributeTargets 枚举的一个或多个元素。 AllowMultiple 参数设置为 true,则返回属性可对单个实体应用多次
AttributeTargets.Class|AttributeTargets.Method
不是位运算的意思. 表示此AttributeUsage类可以应用于类或方法上面. 这些属性是可以自定义的.
4.7 实现自定义属性
在本章前面的章节中我们实现的许多功能都是借助于系统提供的设计时元数据属性支持实现的,如:
显示属性描述信息的Description属性
[Description("描述文本")]
指定属性在属性窗口中类别的Category设计属性
[Category("属性窗口中的类别名称")]
指定属性编辑器的Editor设计属性
[Editor(typeof(FileNameEditor), typeof(UITypeEditor))]
指定属性类型转换器的TypeConverter设计属性
[TypeConverter(typeof(SolidCoordinateConverter))]
这些都是系统提供的,每个属性都有它自己的功能。那么如果我们想自定义一个设计属性,实现自定义的功能,该怎么实现呢?要设计自定义属性,仅需要直接或间接地从System.Attribute派生即可,与传统类功能完全一样。我们既可以使用System.Attribute来定义控件设计期控制,也可以用System.Attribute指定运行时的控制。
本节就以一个示例演示控件中的设计属性是怎么实现的。首先还是先说明一下本节控件属性要实现的功能,如图4-35所示。
此控件具有一个Num属性,允许开发人员指定一个值。在控件的属性上指定了一个NumValidate类型的验证属性,该属性需要传入两个参数,供开发人员指定区间,如果在属性窗口中指定的属性不在区间内,则会有警告提示(如图4-35中红色警告提示)。
或许读者会想这不就是一个验证输入的简单功能吗?这里与我们之前做的验证的情况是不一样的。之前我们经常用的验证方式是页面在浏览器中运行时的验证,即对用户输入的验证;而这里是在IDE设计器界面验证,是在控件设计模式下的验证,是对使用控件的开发人员进行输入验证,而不是对最终用户输入验证。
本示例就是用来讲解怎样在设计模式下设置和获取我们自己定义的设计属性。还是从代码开始,NumValidate属性的源代码如下:
/// <summary>
/// 自定义属性类(实现验证功能)
/// </summary>
[AttributeUsage(AttributeTargets.Property,AllowMultiple=true,Inherited=true)]
//http://blog.csdn.net/ChengKing/archive/2008/08/18/2792440.aspx
public class NumValidateAttribute : Attribute
{
/// <summary>
图4-35
/// 构造方法
/// </summary>
/// <param name="intMinValue">最小值</param>
/// <param name="intMaxValue">最大值</param>
public NumValidateAttribute(int intMinValue, int intMaxValue)
{
this.intMinValue = intMinValue;
this.intMaxValue = intMaxValue;
} private int intMinValue;
/// <summary>
/// 最大值
/// </summary>
public int MinValue
{
get
{
return intMinValue;
}
} private int intMaxValue;
/// <summary>
/// 最小值
/// </summary>
public int MaxValue
{
get
{
return intMaxValue;
}
} /// <summary>
/// 执行验证
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public bool ValidateResult(int value)
{
if (this.intMinValue <= value && value <= this.intMaxValue)
{
return true;
}
else
{
return false;
}
}
}
代码中验证类名为NumValidateAttribute,从System.Attribute派生而来,有些时候根据需要间接继承System.Attribute也是可以的。
类中必须有一个带两个参数的构造方法,分别表示验证范围的最大值和最小值,然后定义两个属性:MinValue和MaxValue,分别存储验证范围的最小值和最大值。最后面的方法ValidateResult是主要的验证方法,它有一个参数,表示要验证的值,如果此值在最大值和最小值区间,则返回True,表示是合法输入;否则,返回False,表示验证失败。
验证类NumValidateAttribute上方有一个很重要的设计时属性:
[AttributeUsage(AttributeTargets.Property,AllowMultiple=true,Inherited=true)]
AttributeUsage完整命名为System.AttributeUsageAttribute,它包含三个对自定义属性的创建具有重要意义的成员:AttributeTargets、AllowMultiple和Inherited。该类主要说明NumValidateAttribute的用法(作用于类还是属性,是否允许被继承,等等)。我们只需要指定各个参数即可,如果使用位置不正确,系统会自动提示警告信息。
AttributeTargets指定可以对应用程序的哪些元素应用此属性。在前面的示例中指定了AttributeTargets.Property,指示该属性只可以应用到类中的属性,还可以指定AttributeTargets.Class,表示属性只可以应用于类元素;或指定AttributeTargets.Method,属性只可以应用于某个方法。还可通过 "|" 设置AttributeTargets的多个实例。下列代码段指定自定义属性可应用到任何类或方法:
[AttributeUsage (AttributeTargets.Class | AttributeTargets.Method)]。
如果某个属性可以应用到 AttributeTargets下的所有类型,则需要作如下设置即可:
[AttributeUsage (AttributeTargets.All)]
AttributeUsage枚举类应用的范围不仅仅包括类和属性,共有15个可应用元素,下面是它的源代码:
// 摘要:
// 指定哪些应用程序元素可以对它们应用属性
[Serializable]
[ComVisible(true)]
[Flags]
//http://blog.csdn.net/ChengKing/archive/2008/08/18/2792440.aspx
public enum AttributeTargets
{
// 摘要:
// 可以对程序集应用属性
Assembly = 1,
//
// 摘要:
// 可以对模块应用属性
Module = 2,
//
// 摘要:
// 可以对类应用属性
Class = 4,
//
// 摘要:
// 可以对结构应用属性,即值类型
Struct = 8,
//
// 摘要:
// 可以对枚举应用属性
Enum = 16,
//
// 摘要:
// 可以对构造函数应用属性
Constructor = 32,
//
// 摘要:
// 可以对方法应用属性
Method = 64,
//
// 摘要:
// 可以对属性 (Property) 应用属性 (Attribute)
Property = 128,
//
// 摘要:
// 可以对字段应用属性
Field = 256,
//
// 摘要:
// 可以对事件应用属性
Event = 512,
//
// 摘要:
// 可以对接口应用属性
Interface = 1024,
//
// 摘要:
// 可以对参数应用属性
Parameter = 2048,
//
// 摘要:
// 可以对委托应用属性
Delegate = 4096,
//
// 摘要:
// 可以对返回值应用属性
ReturnValue = 8192,
//
// 摘要:
// 可以对泛型参数应用属性
GenericParameter = 16384,
//
// 摘要:
// 可以对任何应用程序元素应用属性
All = 32767,
}
[CustomAttribute]
[CustomAttribute]
public void Method()
{
//... …
}
最后一个参数Inherited,也是bool类型的。我们可以使用该属性来控制我们的自定义attribute类的继承规则,该属性标识我们的自定义Attribute在应用到元素(别名A)时,是否可以由派生类(继承于A所属的类)继承。如果设置为True,则可以被继承;反之,不可以被继承。
更深一点理解,AllowMultiple和 Inherited还可以组合使用,完成我们需要的设置功能。如果AllowMultiple=True,且Inherited=True,且基类A和B类(继承A类)中都有相同名称的一个属性,则实际上B类中有两个相同名称的属性,即两个不同的实例,自己定义的一个和从基类继承来的一个;如果设置AllowMultiple=False, Inherited=True,且基类A和B类(继承A类)中都有相同名称的一个属性,则这时B类中只有一个属性,即自己定义的实例,因为AllowMultiple=False指定不允许多实例并存,系统只能用B类定义的属性重写A类的属性定义。如果不按正确方式使用,编译程序会提示警告信息。
到此自定义属性类就已经讲解完了,下面讲解一下此属性类是怎么使用的。笔者专门做了个控件来讲解属性类在控件中是怎么使用的,主控件源代码如下:
[DefaultProperty("Num")]
[ToolboxData("<{0}:CustomPropertyControl runat=server></{0}:CustomPropertyControl>")]
//http://blog.csdn.net/ChengKing/archive/2008/08/18/2792440.aspx
public class CustomPropertyControl : WebControl
{
TextBox tb;
int intNum = 0;
[Category("Appearance")]
[NumValidate(0, 10)]
[Description("输入值范围(0~10)")]
public int Num
{
get
{
return intNum;
} set
{
intNum = value;
}
}
protected override void Render(HtmlTextWriter writer)
{
Table t = new Table();
t.CellPadding = 0;
t.CellSpacing = 0;
TableRow tr = new TableRow(); TableCell td_left = new TableCell();
tb = new TextBox();
tb.Text = this.intNum.ToString();
td_left.Controls.Add(tb);
tr.Controls.Add(td_left); NumValidateAttribute numValidateAttribute = this.GetNumValidate Arribute();
if (numValidateAttribute.ValidateResult(this.Num) == false)
{
TableCell td_right = new TableCell();
Label lb = new Label();
lb.ForeColor = System.Drawing.Color.Red;
lb.Text = "值输入范围必须在:" + numValidateAttribute.MinValue. ToString
() + "~" + numValidateAttribute.MaxValue.ToString() + "之间!";
td_right.Controls.Add(lb);
tr.Controls.Add(td_right);
}
t.Controls.Add(tr); t.RenderControl(writer);
} private NumValidateAttribute GetNumValidateArribute()
{
System.Type type = this.GetType();
PropertyInfo property = type.GetProperty("Num");
object[] attrs = (object[])property.GetCustomAttributes(true);
foreach (Attribute attr in attrs)
{
if (attr is NumValidateAttribute)
{
return attr as NumValidateAttribute;
}
}
return null;
}
}
主控件输出一个文本框,开发人员在设计器属性窗口中可以修改文本框的值。控件中的属性Num,就是用来存储文本框的值的。Num属性使用了我们刚刚定义的自定义属性验证证类NumValidateAttribute:
[NumValidate(0, 10)]
注意在使用时,关键字使用的不是我们定义的完整类名。实际上这里使用 [NumValidate(0, 10)] 和 [NumValidateAttribute(0, 10)] 都是可以的,系统都会把后缀Attribute省略,而且智能提示也会省略Attribute,因此我们在使用时也把Attribute省略了。
我们设置NumValidate属性并传入两个参数:0和10,以及Num的类型为int类型,表示要求这个Num属性必须是0 ~ 10之间的整型数值。在设计模式和运行模式执行时,系统会把0和10作为NumValidateAttribute类的构造参数创建实例。
接下来是Render方法,在Render方法中主要执行两个功能:一是输出TextBox内容,并嵌套到Table对象中;二是实现对设计期间的输入验证。验证过程代码如下:
NumValidateAttribute numValidateAttribute = this.GetNumValidateArribute();
if (numValidateAttribute.ValidateResult(this.Num) == false)
{
TableCell td_right = new TableCell();
Label lb = new Label();
lb.ForeColor = System.Drawing.Color.Red;
lb.Text = "值输入范围必须在:" + numValidateAttribute.MinValue.ToString() + "~" + numValidateAttribute.MaxValue.ToString() + "之间!";
td_right.Controls.Add(lb);
tr.Controls.Add(td_right);
}
以上代码首先,获取我们在属性上指定的自定义验证属性实例对象,然后以主控件的Num值作为参数,调用验证属性对象的ValidateResult方法进行输入合法验证,如果当前输入值验证失败(Num在我们设定的0~10之间,这里仅模拟验证逻辑),则会在当前行中增加一个单元格,并在单元格中增加一个显示出错警告的Label控件,告知开发人员合法输入值正确范围;反之,验证成功,则不会Render出单元格和提示警告信息Label控件。
接下来说明自定义属性对象实例是怎样获取到的,方法GetNumValidateArribute获取属性对象的代码,其使用反射机制取得。代码如下:
System.Type type = this.GetType();
PropertyInfo property = type.GetProperty("Num");
首先取得当前控件类的类型,再根据类型调用以Num属性为参数,调用GetProperty方法取得取得属性的PropertyInfo对象property, PropertyInfo可以提供对属性元数据的访问。代码如下:
object[] attrs = (object[])property.GetCustomAttributes(true);
foreach (Attribute attr in attrs)
{
if (attr is NumValidateAttribute)
{
return attr as NumValidateAttribute;
}
}
return null;
通过PropertyInfo对象实例的GetCustomAttributes方法获取Num属性的所有自定义属性类实例,放到attrs数组中,再循环遍历数组中每个实例的类型,如果找到有NumValidateAttribute类型的对象实例,则返回此实例;否则,返回null。
GetCustomAttributes方法主要是展示怎样获取属性元素的设计属性实例,如果自定义属性不是应用到属性,而是类或接口或方法等,则获取属性实例方式原理类似,都是通过反射机制实现。这里不作多讲,具体使用时可以查看官方文档。
编译主控件,并放置一个CustomPropertyControl控件到页面中,则可以在属性窗口中通过修改控件Num属性的值来看一下效果,如图4-36所示。
图4-36 属性窗口效果
自定义属性就讲到这里,在主控件类中可以通过this.GetType()方法获取当前控件的类型,再根据类型取得属性,进而取得属性的设计属性Attribute,那么在控件构造器类、控件编辑器类或控件类型转换器类等这样的一些类中是怎样获取到当前主控件类型呢?其实读者可能会想到了,一般在这些特殊类中都会有相应的上下文对象,比如在4.6节讲解的自定义类型转换器中,像ConvertTo,CanConvertFrom等方法都会有个ITypeDescriptorContext类型的上下文参数,基本上我们可能需要的所有信息都能够通过此对象得到,如图4-37所示。
图4-37 智通能感知列表
如上图所示的智能感知列表,可以看到它下面有容器对象、实例,属性描述集合,还有属性描述类等。
效果不太好, word格式和图片都丢失了.
控件属性这章完整内容, 我会在12月份底共享出来供大家学习[待电工出版社编辑稿完成后给我], 将在这里可以看到:
[庖丁解牛:纵向切入Asp.net 3.5控件和组件开发技术--基于VS 2008(兼容VS 2005)/C#]
http://blog.csdn.net/ChengKing/archive/2008/08/18/2792440.aspx