`
leonardleonard
  • 浏览: 776879 次
社区版块
存档分类
最新评论

Attribute在.net编程中的应用

阅读更多
作者:niwalker       出处:csdn

SqlCommandGenerator类的设计

SqlCommandGEnerator类的设计思路就是通过反射得到方法的参数,使用被SqlCommandParameterAttribute标记的参数来装配一个Command实例。

引用的命名空间:

//SqlCommandGenerator.cs

using System;
using System.Reflection;
using System.Data;
using System.Data.SqlClient;
using Debug = System.Diagnostics.Debug;
using StackTrace = System.Diagnostics.StackTrace;


类代码:
namespace DataAccess
{
public sealed class SqlCommandGenerator
{
//私有构造器,不允许使用无参数的构造器构造一个实例
private SqlCommandGenerator()
{
throw new NotSupportedException();
}

//静态只读字段,定义用于返回值的参数名称
public static readonly string ReturnValueParameterName = "RETURN_VALUE";
//静态只读字段,用于不带参数的存储过程
public static readonly object[] NoValues = new object[] {};


public static SqlCommand GenerateCommand(SqlConnection connection,
MethodInfo method, object[] values)
{
//如果没有指定方法名称,从堆栈帧得到方法名称
if (method == null)
method = (MethodInfo) (new StackTrace().GetFrame(1).GetMethod());

// 获取方法传进来的SqlCommandMethodAttribute
// 为了使用该方法来生成一个Command对象,要求有这个Attribute。
SqlCommandMethodAttribute commandAttribute =
(SqlCommandMethodAttribute) Attribute.GetCustomAttribute(method, typeof(SqlCommandMethodAttribute));

Debug.Assert(commandAttribute != null);
Debug.Assert(commandAttribute.CommandType == CommandType.StoredProcedure ||
commandAttribute.CommandType == CommandType.Text);

// 创建一个SqlCommand对象,同时通过指定的attribute对它进行配置。
SqlCommand command = new SqlCommand();
command.Connection = connection;
command.CommandType = commandAttribute.CommandType;

// 获取command的文本,如果没有指定,那么使用方法的名称作为存储过程名称
if (commandAttribute.CommandText.Length == 0)
{
Debug.Assert(commandAttribute.CommandType == CommandType.StoredProcedure);
command.CommandText = method.Name;
}
else
{
command.CommandText = commandAttribute.CommandText;
}

// 调用GeneratorCommandParameters方法,生成command参数,同时添加一个返回值参数
GenerateCommandParameters(command, method, values);
command.Parameters.Add(ReturnValueParameterName, SqlDbType.Int).Direction
=ParameterDirection.ReturnValue;

return command;
}

private static void GenerateCommandParameters(
SqlCommand command, MethodInfo method, object[] values)
{

// 得到所有的参数,通过循环一一进行处理。

ParameterInfo[] methodParameters = method.GetParameters();
int paramIndex = 0;

foreach (ParameterInfo paramInfo in methodParameters)
{
// 忽略掉参数被标记为[NonCommandParameter ]的参数

if (Attribute.IsDefined(paramInfo, typeof(NonCommandParameterAttribute)))
continue;

// 获取参数的SqlParameter attribute,如果没有指定,那么就创建一个并使用它的缺省设置。
SqlParameterAttribute paramAttribute = (SqlParameterAttribute) Attribute.GetCustomAttribute(
paramInfo, typeof(SqlParameterAttribute));

if (paramAttribute == null)
paramAttribute = new SqlParameterAttribute();

//使用attribute的设置来配置一个参数对象。使用那些已经定义的参数值。如果没有定义,那么就从方法
// 的参数来推断它的参数值。
SqlParameter sqlParameter = new SqlParameter();
if (paramAttribute.IsNameDefined)
sqlParameter.ParameterName = paramAttribute.Name;
else
sqlParameter.ParameterName = paramInfo.Name;

if (!sqlParameter.ParameterName.StartsWith("@"))
sqlParameter.ParameterName = "@" + sqlParameter.ParameterName;

if (paramAttribute.IsTypeDefined)
sqlParameter.SqlDbType = paramAttribute.SqlDbType;

if (paramAttribute.IsSizeDefined)
sqlParameter.Size = paramAttribute.Size;

if (paramAttribute.IsScaleDefined)
sqlParameter.Scale = paramAttribute.Scale;

if (paramAttribute.IsPrecisionDefined)
sqlParameter.Precision = paramAttribute.Precision;

if (paramAttribute.IsDirectionDefined)
{
sqlParameter.Direction = paramAttribute.Direction;
}
else
{
if (paramInfo.ParameterType.IsByRef)
{
sqlParameter.Direction = paramInfo.IsOut ?
ParameterDirection.Output :
ParameterDirection.InputOutput;
}
else
{
sqlParameter.Direction = ParameterDirection.Input;
}
}

// 检测是否提供的足够的参数对象值
Debug.Assert(paramIndex < values.Length);

//把相应的对象值赋于参数。
sqlParameter.Value = values[paramIndex];
command.Parameters.Add(sqlParameter);


paramIndex++;
}

//检测是否有多余的参数对象值
Debug.Assert(paramIndex == values.Length);
}
}
}

必要的工作终于完成了。SqlCommandGenerator中的代码都加上了注释,所以并不难读懂。下面我们进入最后的一步,那就是使用新的方法来实现上一节我们一开始显示个那个AddCustomer的方法。

重构新的AddCustomer代码:

[ SqlCommandMethod(CommandType.StoredProcedure) ]
public void AddCustomer( [NonCommandParameter] SqlConnection connection,
[SqlParameter(50)] string customerName,
[SqlParameter(20)] string country,
[SqlParameter(20)] string province,
[SqlParameter(20)] string city,
[SqlParameter(60)] string address,
[SqlParameter(16)] string telephone,
out int customerId )
{
customerId=0; //需要初始化输出参数
//调用Command生成器生成SqlCommand实例
SqlCommand command = SqlCommandGenerator.GenerateCommand( connection, null, new object[]
{customerName,country,province,city,address,telephone,customerId } );

connection.Open();
command.ExecuteNonQuery();
connection.Close();

//必须明确返回输出参数的值
customerId=(int)command.Parameters["@CustomerId"].Value;
}

代码中必须注意的就是out参数,需要事先进行初始化,并在Command执行操作以后,把参数值传回给它。受益于Attribute,使我们摆脱了那种编写大量枯燥代码编程生涯。 我们甚至还可以使用Sql存储过程来编写生成整个方法的代码,如果那样做的话,可就大大节省了你的时间了,上一节和这一节中所示的代码,你可以把它们单独编译成一个组件,这样就可以在你的项目中不断的重用它们了。从下一节开始,我们将更深层次的介绍Attribute的应用,请继续关注。
用于参数的Attribute 在编写多层应用程序的时候,你是否为每次要写大量类似的数据访问代码而感到枯燥无味?比如我们需要编写调用存储过程的代码,或者编写T_SQL代码,这些代码往往需要传递各种参数,有的参数个数比较多,一不小心还容易写错。有没有一种一劳永逸的方法?当然,你可以使用MS的Data Access Application Block,也可以使用自己编写的Block。这里向你提供一种另类方法,那就是使用Attribute。

下面的代码是一个调用AddCustomer存储过程的常规方法:


public int AddCustomer(SqlConnection connection,
string customerName,
string country,
string province,
string city,
string address,
string telephone)
{
SqlCommand command=new SqlCommand("AddCustomer", connection);
command.CommandType=CommandType.StoredProcedure;

command.Parameters.Add("@CustomerName",SqlDbType.NVarChar,50).Value=customerName;
command.Parameters.Add("@country",SqlDbType.NVarChar,20).Value=country;
command.Parameters.Add("@Province",SqlDbType.NVarChar,20).Value=province;
command.Parameters.Add("@City",SqlDbType.NVarChar,20).Value=city;
command.Parameters.Add("@Address",SqlDbType.NVarChar,60).Value=address;
command.Parameters.Add("@Telephone",SqlDbType.NvarChar,16).Value=telephone;
command.Parameters.Add("@CustomerId",SqlDbType.Int,4).Direction=ParameterDirection.Output;

connection.Open();
command.ExecuteNonQuery();
connection.Close();

int custId=(int)command.Parameters["@CustomerId"].Value;
return custId;
}

上面的代码,创建一个Command实例,然后添加存储过程的参数,然后调用ExecuteMonQuery方法执行数据的插入操作,最后返回CustomerId。从代码可以看到参数的添加是一种重复单调的工作。如果一个项目有100多个甚至几百个存储过程,作为开发人员的你会不会要想办法偷懒?(反正我会的:-))。

下面开始我们的代码自动生成工程:

我们的目的是根据方法的参数以及方法的名称,自动生成一个Command对象实例,第一步我们要做的就是创建一个SqlParameterAttribute, 代码如下:


SqlCommandParameterAttribute.cs

using System;
using System.Data;
using Debug=System.Diagnostics.Debug;

namespace DataAccess
{
// SqlParemeterAttribute 施加到存储过程参数
[ AttributeUsage(AttributeTargets.Parameter) ]
public class SqlParameterAttribute : Attribute
{
private string name; //参数名称
private bool paramTypeDefined; //是否参数的类型已经定义
private SqlDbType paramType; //参数类型
private int size; //参数尺寸大小
private byte precision; //参数精度
private byte scale; //参数范围
private bool directionDefined; //是否定义了参数方向
private ParameterDirection direction; //参数方向

public SqlParameterAttribute()
{
}

public string Name
{
get { return name == null ? string.Empty : name; }
set { _name = value; }
}

public int Size
{
get { return size; }
set { size = value; }
}

public byte Precision
{
get { return precision; }
set { precision = value; }
}

public byte Scale
{
get { return scale; }
set { scale = value; }
}

public ParameterDirection Direction
{
get
{
Debug.Assert(directionDefined);
return direction;
}
set
{
direction = value;
directionDefined = true;
}
}

public SqlDbType SqlDbType
{
get
{
Debug.Assert(paramTypeDefined);
return paramType;
}
set
{
paramType = value;
paramTypeDefined = true;
}
}

public bool IsNameDefined
{
get { return name != null && name.Length != 0; }
}

public bool IsSizeDefined
{
get { return size != 0; }
}

public bool IsTypeDefined
{
get { return paramTypeDefined; }
}

public bool IsDirectionDefined
{
get { return directionDefined; }
}

public bool IsScaleDefined
{
get { return _scale != 0; }
}

public bool IsPrecisionDefined
{
get { return _precision != 0; }
}

...

以上定义了SqlParameterAttribute的字段和相应的属性,为了方便Attribute的使用,我们重载几个构造器,不同的重载构造器用于不用的参数:
...

// 重载构造器,如果方法中对应于存储过程参数名称不同的话,我们用它来设置存储过程的名称
// 其他构造器的目的类似
public SqlParameterAttribute(string name)
{
Name=name;
}

public SqlParameterAttribute(int size)
{
Size=size;
}

public SqlParameterAttribute(SqlDbType paramType)
{
SqlDbType=paramType;
}

public SqlParameterAttribute(string name, SqlDbType paramType)
{
Name = name;
SqlDbType = paramType;
}

public SqlParameterAttribute(SqlDbType paramType, int size)
{
SqlDbType = paramType;
Size = size;
}


public SqlParameterAttribute(string name, int size)
{
Name = name;
Size = size;
}

public SqlParameterAttribute(string name, SqlDbType paramType, int size)
{
Name = name;
SqlDbType = paramType;
Size = size;
}
}
}

为了区分方法中不是存储过程参数的那些参数,比如SqlConnection,我们也需要定义一个非存储过程参数的Attribute:

//NonCommandParameterAttribute.cs

using System;
namespace DataAccess
{
[ AttributeUsage(AttributeTargets.Parameter) ]
public sealed class NonCommandParameterAttribute : Attribute
{
}
}

我们已经完成了SQL的参数Attribute的定义,在创建Command对象生成器之前,让我们考虑这样的一个事实,那就是如果我们数据访问层调用的不是存储过程,也就是说Command的CommandType不是存储过程,而是带有参数的SQL语句,我们想让我们的方法一样可以适合这种情况,同样我们仍然可以使用Attribute,定义一个用于方法的Attribute来表明该方法中的生成的Command的CommandType是存储过程还是SQL文本,下面是新定义的Attribute的代码:

//SqlCommandMethodAttribute.cs

using System;
using System.Data;

namespace Emisonline.DataAccess
{
[AttributeUsage(AttributeTargets.Method)]
public sealed class SqlCommandMethodAttribute : Attribute
{
private string commandText;
private CommandType commandType;

public SqlCommandMethodAttribute( CommandType commandType, string commandText)
{
commandType=commandType;
commandText=commandText;
}

public SqlCommandMethodAttribute(CommandType commandType) : this(commandType, null){}

public string CommandText
{
get
{
return commandText==null ? string.Empty : commandText;
}
set
{
commandText=value;
}
}

public CommandType CommandType
{
get
{
return commandType;
}
set
{
commandType=value;
}
}
}
}


我们的Attribute的定义工作已经全部完成,下一步就是要创建一个用来生成Command对象的类。


.NET Framework中对Attribute的支持是一个全新的功能,这种支持来自它的Attribute类。在你的程序中适当地使用这个类,或者是灵活巧妙地利用这个类,将使你的程序获得某种在以往编程中很难做到的能力。我们来看一个例子:
假如你是一个项目开发小组中的成员,你想要跟踪项目代码检查的信息,通常你可以把代码的检查信息保存在数据库中以便查询;或者把信息写到代码的注释里面,这样可以阅读代码的同时看到代码被检查的信息。我们知道.NET的组件是自描述的,那么是否可以让代码自己来描述它被检查的信息呢?这样我们既可以将信息和代码保存在一起,又可以通过代码的自我描述得到信息。答案就是使用Attribute.
下面的步骤和代码告诉你怎么做:
首先,我们创建一个自定义的Attribute,并且事先设定我们的Attribute将施加在class的元素上面以获取一个类代码的检查信息。


using System;
using System.Reflection;

[AttributeUsage(AttributeTargets.Class)] //还记得上一节的内容吗?
public class CodeReviewAttribute : System.Attribute //定义一个CodeReview的Attribute
{
private string reviewer; //代码检查人
private string date; //检查日期
private string comment; //检查结果信息

//参数构造器
public CodeReviewAttribute(string reviewer, string date)
{
this.reviewer=reviewer;
this.date=date;
}

public string Reviewer
{
get
{
return reviewer;
}
}

public string Date
{
get
{
return date;
}
}

public string Comment
{
get
{
return comment;
}
set
{
comment=value;
}
}
}


我们的自定义CodeReviewAttribute同普通的类没有区别,它从Attribute派生,同时通过AttributeUsage表示我们的Attribute仅可以施加到类元素上。

第二步就是使用我们的CodeReviewAttribute, 假如我们有一个Jack写的类MyClass,检查人Niwalker,检查日期2003年7月9日,于是我们施加Attribute如下:

[CodeReview("Niwalker","2003-7-9",Comment="Jack的代码")]
public class MyClass
{
//类的成员定义
}

当这段代码被编译的时候,编译器会调用CodeReviewAttribute的构造器并且把"Niwalker"和"2003-7-9"分别作为构造器的参数。注意到参数表中还有一个Comment属性的赋值,这是Attribute特有的方式,这里你可以设置更多的Attribute的公共属性(如果有的话),需要指出的是.NET Framework1.0允许向private的属性赋值,但在.NET Framework1.1已经不允许这样做,只能向public的属性赋值。

第三步就是取出我们需要的信息,这是通过.NET的反射来实现的,关于反射的知识,限于篇幅我不打算在这里进行说明,也许我会在以后另外写一篇介绍反射的文章。

class test
{
static void Main(string[] args)
{
System.Reflection.MemberInfo info=typeof(MyClass); //通过反射得到MyClass类的信息

//得到施加在MyClass类上的定制Attribute
CodeReviewAttribute att=
(CodeReviewAttribute)Attribute.GetCustomAttribute(info,typeof(CodeReviewAttribute));
if(att!=null)
{
Console.WriteLine("代码检查人:{0}",att.Reviewer);
Console.WriteLine("检查时间:{0}",att.Date);
Console.WriteLine("注释:{0}",att.Comment);
}
}
}

在上面这个例子中,Attribute扮演着向一个类添加额外信息的角色,它并不影响MyClass类的行为。通过这个例子,我们大致可以知道如何写一个自定义的Attribute,以及如何在应用程序使用它。下一节,我将介绍如何使用Attribute来自动生成ADO.NET的数据访问类的代码。
经常有朋友问,Attribute是什么?它有什么用?好像没有这个东东程序也能运行。实际上在.Net中,Attribute是一个非常重要的组成部分,为了帮助大家理解和掌握Attribute,以及它的使用方法,特地收集了几个Attribute使用的例子,提供给大家参考。

在具体的演示之前,我想先大致介绍一下Attribute。我们知道在类的成员中有property成员,二者在中文中都做属性解释,那么它们到底是不是同一个东西呢?从代码上看,明显不同,首先就是它们的在代码中的位置不同,其次就是写法不同(Attribute必须写在一对方括符中)。

什么是Atrribute
首先,我们肯定Attribute是一个类,下面是msdn文档对它的描述:
公共语言运行时允许你添加类似关键字的描述声明,叫做attributes, 它对程序中的元素进行标注,如类型、字段、方法和属性等。Attributes和Microsoft .NET Framework文件的元数据保存在一起,可以用来向运行时描述你的代码,或者在程序运行的时候影响应用程序的行为。

在.NET中,Attribute被用来处理多种问题,比如序列化、程序的安全特征、防止即时编译器对程序代码进行优化从而代码容易调试等等。下面,我们先来看几个在.NET中标准的属性的使用,稍后我们再回过头来讨论Attribute这个类本身。(文中的代码使用C#编写,但同样适用所有基于.NET的所有语言)

Attribute作为编译器的指令
在C#中存在着一定数量的编译器指令,如:#define DEBUG, #undefine DEBUG, #if等。这些指令专属于C#,而且在数量上是固定的。而Attribute用作编译器指令则不受数量限制。比如下面的三个Attribute:

Conditional:起条件编译的作用,只有满足条件,才允许编译器对它的代码进行编译。一般在程序调试的时候使用。
DllImport:用来标记非.NET的函数,表明该方法在一个外部的DLL中定义。
Obsolete:这个属性用来标记当前的方法已经被废弃,不再使用了。
下面的代码演示了上述三个属性的使用:

#define DEBUG //这里定义条件

using System;
using System.Runtime.InteropServices;
using System.Diagnostics;

namespace AttributeDemo
{
class MainProgramClass
{

[DllImport("User32.dll")]
public static extern int MessageBox(int hParent, string Message, string Caption, int Type);

static void Main(string[] args)
{
DisplayRunningMessage();
DisplayDebugMessage();

MessageBox(0,"Hello","Message",0);

Console.ReadLine();
}

[Conditional("DEBUG")]
private static void DisplayRunningMessage()
{
Console.WriteLine("开始运行Main子程序。当前时间是"+DateTime.Now);
}

[Conditional("DEBUG")]
[Obsolete]
private static void DisplayDebugMessage()
{
Console.WriteLine("开始Main子程序");
}
}
}


如果在一个程序元素前面声明一个Attribute,那么就表示这个Attribute被施加到该元素上,前面的代码,[DllImport]施加到MessageBox函数上, [Conditional]施加到DisplayRuntimeMessage方法和DisplayDebugMessage方法,[Obsolete]施加到DisplayDebugMessage方法上。

根据上面涉及到的三个Attribute的说明,我们可以猜到程序运行的时候产生的输出:DllImport Attribute表明了MessageBox是User32.DLL中的函数,这样我们就可以像内部方法一样调用这个函数。

重要的一点就是Attribute就是一个类,所以DllImport也是一个类,Attribute类是在编译的时候被实例化的,而不是像通常的类那样在运行时候才实例化。Attribute实例化的时候根据该Attribute类的设计可以带参数,也可以不带参数,比如DllImport就带有"User32.dll"的参数。Conditional对满足参数的定义条件的代码进行编译,如果没有定义DEBUG,那么该方法将不被编译,读者可以把#define DEBUG一行注释掉看看输出的结果(release版本,在Debug版本中Conditional的debug总是成立的)。Obsolete表明了DispalyDebugMessage方法已经过时了,它有一个更好的方法来代替它,当我们的程序调用一个声明了Obsolete的方法时,那么编译器会给出信息,Obsolete还有其他两个重载的版本。大家可以参考msdn中关于的ObsoleteAttribute 类的描述。

Attribute类
除了.NET提供的那些Attribute派生类之外,我们可以自定义我们自己的Attribute,所有自定义的Attribute必须从Attribute类派生。现在我们来看一下Attribute 类的细节:

protected Attribute(): 保护的构造器,只能被Attribute的派生类调用。

三个静态方法:

static Attribute GetCustomAttribute():这个方法有8种重载的版本,它被用来取出施加在类成员上指定类型的Attribute。

static Attribute[] GetCustomAttributes(): 这个方法有16种重载版本,用来取出施加在类成员上指定类型的Attribute数组。

static bool IsDefined():由八种重载版本,看是否指定类型的定制attribute被施加到类的成员上面。

实例方法:

bool IsDefaultAttribute(): 如果Attribute的值是默认的值,那么返回true。

bool Match():表明这个Attribute实例是否等于一个指定的对象。

公共属性: TypeId: 得到一个唯一的标识,这个标识被用来区分同一个Attribute的不同实例。

我们简单地介绍了Attribute类的方法和属性,还有一些是从object继承来的。这里就不列出来了。

下面介绍如何自定义一个Attribute: 自定义一个Attribute并不需要特别的知识,其实就和编写一个类差不多。自定义的Attribute必须直接或者间接地从Attribute这个类派生,如:

public MyCustomAttribute : Attribute { ... }

这里需要指出的是Attribute的命名规范,也就是你的Attribute的类名+"Attribute",当你的Attribute施加到一个程序的元素上的时候,编译器先查找你的Attribute的定义,如果没有找到,那么它就会查找“Attribute名称"+Attribute的定义。如果都没有找到,那么编译器就报错。

对于一个自定义的Attribute,你可以通过AttributeUsage的Attribute来限定你的Attribute 所施加的元素的类型。代码形式如下: [AttriubteUsage(参数设置)] public 自定义Attribute : Attribute { ... }

非常有意思的是,AttributeUsage本身也是一个Attribute,这是专门施加在Attribute类的Attribute. AttributeUsage自然也是从Attribute派生,它有一个带参数的构造器,这个参数是AttributeTargets的枚举类型。下面是AttributeTargets 的定义:

public enum AttributeTargets
{
All=16383,
Assembly=1,
Module=2,
Class=4,
Struct=8,
Enum=16,
Constructor=32,
Method=64,
Property=128,
Field=256,
Event=512,
Interface=1024,
Parameter=2048,
Delegate=4096,
ReturnValue=8192
}


作为参数的AttributeTarges的值允许通过“或”操作来进行多个值得组合,如果你没有指定参数,那么默认参数就是All 。 AttributeUsage除了继承Attribute 的方法和属性之外,还定义了以下三个属性:

AllowMultiple: 读取或者设置这个属性,表示是否可以对一个程序元素施加多个Attribute 。

Inherited:读取或者设置这个属性,表示是否施加的Attribute 可以被派生类继承或者重载。

ValidOn: 读取或者设置这个属性,指明Attribute 可以被施加的元素的类型。

AttributeUsage 的使用例子:
using System;
namespace AttTargsCS
{

// 该Attribute只对类有效.
[AttributeUsage(AttributeTargets.Class)]
public class ClassTargetAttribute : Attribute
{
}


// 该Attribute只对方法有效.
[AttributeUsage(AttributeTargets.Method)]
public class MethodTargetAttribute : Attribute
{
}


// 该Attribute只对构造器有效。
[AttributeUsage(AttributeTargets.Constructor)]
public class ConstructorTargetAttribute : Attribute
{
}


// 该Attribute只对字段有效.
[AttributeUsage(AttributeTargets.Field)]
public class FieldTargetAttribute : Attribute
{
}


// 该Attribute对类或者方法有效(组合).
[AttributeUsage(AttributeTargets.Class|AttributeTargets.Method)]
public class ClassMethodTargetAttribute : Attribute
{
}


// 该Attribute对所有的元素有效.
[AttributeUsage(AttributeTargets.All)]
public class AllTargetsAttribute : Attribute
{
}

//上面定义的Attribute施加到程序元素上的用法
[ClassTarget] //施加到类
[ClassMethodTarget]//施加到类
[AllTargets] //施加到类
public class TestClassAttribute
{
[ConstructorTarget] //施加到构造器
[AllTargets] //施加到构造器
TestClassAttribute()
{
}

[MethodTarget] //施加到方法
[ClassMethodTarget] //施加到方法
[AllTargets] //施加到方法
public void Method1()
{
}

[FieldTarget] //施加到字段
[AllTargets] //施加到字段
public int myInt;

static void Main(string[] args)
{
}
}
}




至此,我们介绍了有关Attribute类和它们的代码格式。你一定想知道到底如何在你的应用程序中使用Attribute,如果仅仅是前面介绍的内容,还是不足以说明Attribute有什么实用价值的话,那么从后面的章节开始我们将介绍几个Attribute的不同用法,相信你一定会对Attribute有一个新的了解。(待续)

分享到:
评论

相关推荐

    Attribute在.net编程中的应用(全).doc

    Attribute在.net编程中的应用(全).doc ,.net的高级特性,类似JAVA中的标注。

    Attribute在.net编程中的应用(全)

    此文档详细的介绍了.NET下 自定义Attribute的应用,对于理解.NET AOP下的技术实现非常有帮助

    ASP.NET编程之道.part1.rar

    谬误08 .NET中的应用程序域和操作系统中的进程完全相同 谬误09 C#中没有全局变量 谬误10 .NET和SQL Server中“空值”是一回事 谬误11 C#的结构和C++的完全一样 谬误12 方法中只有引用类型的参数才能实现引用传递 ...

    ASP.NET的网页代码模型及生命周期

    在ASP.NET中,可以创建ASP.NET网站和ASP.NET应用程序,但是ASP.NET网站和ASP.NET应用程序开发过程和编译过程是有区别的。ASP.NET应用程序主要有以下特点: q 可以将ASP.NET应用程序拆分成多个项目以方便开发,管理和...

    中美 IT 培训 C# Asp.net 全套笔记1

    价值一万八的中美 IT 培训笔记一万多培训费的资料,北京权威的.NET培训机构】 【认真学习后你一定能成为优秀的.net程序员】 学习对象:1.大专及大专以上理工科...在整个学习过程中有四次考试,占四个周六的时间。

    中美 IT 培训 C# Asp.net 笔记3

    C# 基本语法、面向对象的思想、数据结构和算法以及设计模式(120课时) 详细介绍.Net Framework、C# 基本语法、编程规范和编程技巧、面向对象的认识问题和分析问题的思想、以及数据结构和常用算法,学习单件模式、...

    C#高级教程_特性在编程中的应用_研究报告

    为了能了充分的理解特性,我们先从.net框架中已经有的特性开始来观察。请看下⾯的代码,下⾯的代码是通过VS按F12转到定义所得到 的,我们可以看到,他定义为了⼀个class,说明特性就是⼀个类。这个类⽐较特殊,可以...

    中美 IT 培训 C# Asp.net 笔记2

    一万多培训费的资料,北京权威的.NET培训机构】 【认真学习后你一定能成为优秀的.net程序员】 学习对象:1.大专及大专以上理工科学历,或有相当学历的理工科教育...在整个学习过程中有四次考试,占四个周六的时间。

    亮剑.NET深入体验与实战精要2

    3.4 ASP.NET编程中的技巧 142 3.4.1 页面之间传值的7种方法 142 3.4.2 get与post方法的区别 146 3.4.3 ASP.NET服务器控件和 HTML控件的区别 146 3.4.4 Server.Transfer和Response.Redirect的区别 148 3.4.5 刷新...

    net学习笔记及其他代码应用

    30.简要谈一下您对微软.NET 构架下remoting和webservice两项技术的理解以及实际中的应用。 答:WS主要是可利用HTTP,穿透防火墙。而Remoting可以利用TCP/IP,二进制传送提高效率。 31.公司要求开发一个继承System....

    亮剑.NET深入体验与实战精要3

    3.4 ASP.NET编程中的技巧 142 3.4.1 页面之间传值的7种方法 142 3.4.2 get与post方法的区别 146 3.4.3 ASP.NET服务器控件和 HTML控件的区别 146 3.4.4 Server.Transfer和Response.Redirect的区别 148 3.4.5 刷新...

    ASP.NET开发实战1200例(第Ⅰ卷)第三章

    类中应用 127 3.2 神秘金字塔——封装特性 128 实例082 使用传统的访问方法和修改方法进行 类的封装 128 实例083 另一种形式的封装:类属性 (非静态属性) 130 实例084 另一种形式的封装:类属性 (静态属性) 131...

    CoreAOP:.NET Core的面向方面的编程

    CoreAOP使用.NET Core和Microsoft的依赖注入进行面向方面的编程。 该库允许您通过定义属性并将其应用于接口来扩展接口功能。 [ Profile ]public interface IMyService { [ Log ] bool MyMethod ();} 通过实现基类来...

    Visual_Studio.NET相关词汇中英翻译

    Attributed Programming 属性化编程 Attributes Property Attributes 属性 Authentication 身份验证 authorable 可创作(的) Auto completion for commands 自动完成命令 Auto Increment 自动增加 Auto Syntax ...

    值类型与引用类型理论内容.part01.rar

    重点讲叙VS2005的新功能实现Web编程) &lt;br&gt;培养目标:IT人才市场紧缺的精通.Net应用开发的软件技术人才。 精通C#.Net、ASP.Net、ADO.Net、AJAX、WEB2.0、XML、JavaScript、SQL Server 2000、Web Service、...

    值类型与引用类型理论内容.part05.rar

    重点讲叙VS2005的新功能实现Web编程) &lt;br&gt;培养目标:IT人才市场紧缺的精通.Net应用开发的软件技术人才。 精通C#.Net、ASP.Net、ADO.Net、AJAX、WEB2.0、XML、JavaScript、SQL Server 2000、Web Service、...

    LINQ 实战 1/11

    本书第一部分介绍了LINQ技术及C#和VB为此提供的新语言特性,第二、三、四部分详细介绍了LINQ的三大主要功能LINQ to Objects、LINQ to SQL、LINQ to XML,第五部分研究了LINQ的可扩展性、在应用程序中使用各种LINQ...

    CODESYS在线教学第一课.rar

    CODESYS 软件工具包是一款基于先进的.NET 架构和 IEC 61131- 3 国际编程标准的、 面向工业 4.0及物联网应用的软件开发平台。CODESYS 软件开发平台的独特优势是用户使用此单一软件工具套件就可以实现一个完整的工业...

Global site tag (gtag.js) - Google Analytics