- 浏览: 812206 次
-
文章分类
最新评论
-
coosummer:
推荐使用http://buttoncssgenerator.c ...
几个漂亮的Button的CSS -
leonardleonard:
现在网站 放到 windows 2008 貌似 攻击少了
网站常被攻击 -
leonardleonard:
复制的
在C#里实现DATAGRID的打印预览和打印 -
spp_1987:
看着 头疼 本来就是头难受
在C#里实现DATAGRID的打印预览和打印 -
spp_1987:
大哥 代码太乱啊 ???
在C#里实现DATAGRID的打印预览和打印
作者:niwalker | 出处:csdn |
|
下面的代码是一个调用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。我们知道在类的成员中有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编程中的应用详解 #### 一、Attribute概述 在.NET编程中,Attribute是一个极为重要的特性,它类似于Java中的注解。Attribute主要用于为.NET框架中的类型、字段、方法和属性等添加元数据信息。...
此文档详细的介绍了.NET下 自定义Attribute的应用,对于理解.NET AOP下的技术实现非常有帮助
在.NET中,Attribute的应用广泛且灵活。例如,`[Serializable]`用于标记类以便进行序列化;`[CLSCompliant(true)]`确保类型遵循公共语言规范(CLS);`[DebuggerStepThrough]`指示调试器不应步入该方法。这些...
在.NET框架中,Attribute是一种元数据,用于向编译器、IDE、运行时环境等提供额外的信息。...通过学习这些资料,你可以更深入地理解Attribute的高级应用,以及如何在.NET环境中实现方法调用的拦截。
《精通C#.NET编程》是一本专为C#初学者及进阶者设计的书籍,旨在帮助读者深入理解和掌握这门强大的编程语言。C#,全称C Sharp,是由微软公司开发的一种面向对象的编程语言,它在.NET框架下运行,广泛应用于Windows...
在.NET框架中,属性(Attribute)是一种元数据,可以附加到程序元素,如类、方法、属性等,为编译器、运行时环境或其他工具提供额外的信息。它们是编程中的一个重要概念,允许开发者向代码中添加非执行性的描述性...
【ASP.NET编程知识】在.NET Core中实现字段和属性注入是一种常见的依赖注入(Dependency Injection,简称DI)方式,它能够帮助开发者创建松耦合、可测试且易于维护的代码。在.NET Core中,内置的依赖注入容器...
XSS 攻击全称为跨站脚本攻击,它是一种在 Web 应用中的计算机安全漏洞。XSS 攻击允许恶意用户将代码植入到提供给其他用户使用的页面中,从而导致安全漏洞。 二、使用 HtmlSanitizer 库防御 XSS 攻击 HtmlSanitizer...
首先,路由在 ASP.NET Core 中有两种主要模式:基于约定(Conventional)和基于特性(Attribute-based)。基于约定的路由通常在全局配置中定义,适用于大多数情况,而基于特性的路由允许我们在控制器或动作方法上...
在 ASP.NET MVC 中,可以使用 `MetadataType` attribute 来实现实体模型验证。例如,在上面的代码中,我们使用了 `MetadataType` attribute 来指定实体模型的验证规则。这样,在添加或编辑实体时,系统将自动进行...
AspectCore是一个适用于Asp.Net Core平台的轻量级Aop(Aspect-oriented programming)解决方案,它更好地遵循Asp.Net Core的模块化开发理念,使用AspectCore可以更容易构建低耦合、易扩展的Web应用程序。AspectCore...
在ASP.NET Core中,实现自定义WebApi模型验证是提升应用程序数据完整性和安全性的重要步骤。传统的ASP.NET Framework中,我们通常使用`ModelState.IsValid`来检查模型是否符合预设的验证规则,或者通过实现`...
这门课程涵盖了从基础到进阶的各种主题,帮助学习者掌握.NET开发的精髓,提升编程技能,从而在实际项目中发挥更大的效能。 .NET平台是微软推出的一个开源、跨平台的应用程序开发框架,它提供了丰富的类库和工具,...
1. **面向对象编程**:深入讲解类、对象、接口、继承、多态等面向对象编程的核心概念,以及如何在C#中有效地应用它们。 2. **泛型**:介绍如何使用泛型来创建类型安全且可重用的数据结构,如列表、队列和堆栈,以及...
ASP.NET MVC权限控制是指在ASP.NET MVC应用程序中对用户的操作权限进行控制和限制,以确保只有授权用户才能访问和操作指定的资源。权限控制可以通过多种方式实现,包括使用Controller和Action、使用Filter、使用...
本课程旨在帮助学生深入了解 .NET 平台下的软件系统分层开发技巧,通过一系列章节的学习,学生将掌握关键的英语术语及其在 .NET 开发中的应用。 **第一章:基础概念** - **assembly装配**:在 .NET 中,assembly ...
谬误08 .NET中的应用程序域和操作系统中的进程完全相同 谬误09 C#中没有全局变量 谬误10 .NET和SQL Server中“空值”是一回事 谬误11 C#的结构和C++的完全一样 谬误12 方法中只有引用类型的参数才能实现引用传递 ...
Attribute标记属性在.NET框架中扮演着重要的角色,它是元数据的一部分,允许我们在代码中附加信息,这些信息在程序运行时可以被编译器、运行时或其他工具读取和使用。Attribute提供了一种灵活的方式来注解类、方法、...