使用自定义属性进行类数据绑定






3.40/5 (2投票s)
本文旨在介绍自定义属性,并展示如何使用它们来创建一个轻量级的数据访问层。
引言
阅读完本文后,您应该能够熟练使用自定义属性。
本文重点介绍如何使用它们来创建一个快速、灵活的数据绑定机制。
先决条件/知识
需要对 ADO.NET 和反射有基本的了解才能理解本文。
理解属性
属性用于向类中的任何元素(包括类本身)添加额外的元数据。
如果您曾经自定义过类的 XML 序列化,那么您就已经使用过属性。任何属性的语法是
[<Attribute>(<attribute values>)] <target element>
定义属性的语法是在将定义您的自定义的类之前放置以下 System 属性。
[AttributeUsage(AttributeTargets.<ElementThisCanApplyTo>,
AllowMultiple = (true | false)]
Attribute 本身可以针对类、构造函数、字段、方法、属性或所有(这意味着该属性可以应用于任何内容,但您需要小心,具体取决于您使用该属性指示的内容)。 属性的类定义非常简单。 类的构造函数决定了将属性应用于元素时可以使用的有效签名。 坚持下去,当我们看看如何实现您的第一个自定义属性时,这一切都会变得清晰起来。 属性类本质上是一个自定义数据结构,您将使用它将一些元数据附加到类元素以供以后检索。 让我们看看我们将用于数据绑定的两个自定义属性。
// This custom attribute will be used to
// relate a data table name to the class definition
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class ClassDataTable : Attribute
{
private string m_strDataTableName = "";
public string TableName
{
get{return m_strDataTableName;}
set{m_strDataTableName=value;}
}
public ClassDataTable(string strDataTableName)
{
m_strDataTableName = strDataTableName;
}
}
//This custom attribute will be used to relate a column name to a
//field (property only)
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class FieldDataColumn : Attribute
{ private string m_strFieldColumnName = "";
public string ColumnName
{
get{return m_strFieldColumnName;}
set{m_strFieldColumnName = value;}
}
public FieldDataColumn(string strFieldColumnName)
{
m_strFieldColumnName = strFieldColumnName;
}
现在我们有了自定义属性,让我们将它们应用于一个新的类对象。
[ClassDataTable("People")]
public class Person
{
private string m_strFirstName = "";
private string m_strLastName = "";
private int m_intAge = 0;
[FieldDataColumn("FirstName")]
public string FirstName
{
get{return m_strFirstName;}
set{m_strFirstName = value;}
}
[FieldDataColumn("LastName")]
public string LastName
{
get{return m_strLastName;}
set{m_strLastName = value;}
}
[FieldDataColumn("Age")]
public int Age
{
get{return m_intAge;}
set{m_intAge = value;}
}
}
读取自定义属性
也许您还没有感到兴奋,毕竟,我们所做的只是将字符串附加到类中的元数据中,您甚至不确定应该如何使用它(或如何访问它)。 别担心,它会变得有趣起来。
让我们创建一个具有一些静态功能的类,该功能将检索我们刚刚附加的元数据。 我要预先说明的是,以下类可以并且应该被抽象成更通用的东西(并且最终会有一篇文章介绍它),但现在,我们将保持简单,只关注手头的任务。
如果您对反射不熟悉甚至不了解,好消息是您将被介绍。 不过,在您完成本文后,我建议您认真阅读关于 .NET Framework 中最强大的功能之一的文章。
我们需要某种方法来获取我们通过新的自定义属性附加到类的元数据,因此我们将创建一个名为 AttributeReader
的新类,并为其提供以下方法:GetBoundTable
和 GetBoundColumn
。
public class AttributeReader
{
//Reads the ClassDataTable custom attribute from the object instance's
//metadata and returns the table name within the ClassDataTable
public static string GetBoundTable(object objTarget)
{
Type objType = objTarget.GetType();
ClassDataTable objBoundTable = (ClassDataTable)
objType.GetClassAttributeByType (objTarget, typeof(ClassDataTable))[0];
return objBoundTable.TableName;
}
//Reads the FieldDataColumn custom attribute from the object instance's
//metadata and returns the column name within the FieldDataTable
public static string GetBoundColumn(object objTarget,
string strFieldName)
{
Type objType = objTarget.GetType();
PropertyInfo objField = objType.GetProperty(strFieldName);
FieldDataColumn objBoundColumn = (FieldDataColumn)
objField.GetCustomAttributes (typeof(FieldDataColumn), true)[0];
return objBoundColumn.ColumnName;
}
}
现在开始...
现在我们已经定义了自定义属性,应用它们的类对象,以及之后读取它们的方法,这是一个简短的列表,演示了所有这些是如何使用的。 为了将所有这些一起测试,您需要包含上面的类列表以及此列表,以创建一个小的控制台应用程序,该应用程序应该为您提供一个前进的基础。
我希望这篇文章对您有所帮助,并帮助您在未来创建更好的数据层。
请记住,本文中的代码旨在向您展示使用自定义属性进行数据绑定的原理,并且所有代码都应进行优化,以便它实用并适用于更多情况。
public class CustomAttributeTesting
{
public static void Main()
{
//First we'll create a data table and fill it with a test row
DataSet objSet = CreateDataSet();
//Retrieve a Person instance from the binding function
Person objPerson = GetObjectFromBinding(objSet);
//Output the values of the objPerson instance
Console.WriteLine("First Name: " + objPerson.FirstName +
"\nLast Name: " + objPerson.LastName +
"\nAge: " + objPerson.Age.ToString());
Console.WriteLine("Press Any Key To Continue");
Console.ReadKey();
}
public static DataSet CreateDataSet()
{
DataSet objSet = new DataSet();
DataTable objTable = new DataTable("People");
objTable.Columns.Add("FirstName", typeof(string));
objTable.Columns.Add("LastName", typeof(string));
objTable.Columns.Add("Age", typeof(int));
objTable.Rows.Add(new object[] {"Alex", "Robson", 27});
objSet.Tables.Add(objTable);
return objSet;
}
//This function performs the binding. It only works against the first
//row in the table.
public static Person GetObjectFromBinding(DataSet objSet)
{
Person objPerson = new Person();
string strTableName = AttributeReader.GetBoundTable(objPerson);
DataTable objTable = objSet.Tables[strTableName];
DataRow objRow = objTable.Rows[0];
string strColumnName = "";
//Although it may seem like overkill for the Person class,
//when you get into larger classes with more members this can
//be a compact way to perform the binding.
foreach (PropertyInfo objField in
typeof(Person).GetProperties())
{
strColumnName = AttributeReader.GetBoundColumn (objPerson, objField.Name);
objField.SetValue(objPerson, Convert.ChangeType (objRow[strColumnName],
objField.PropertyType), null);
}
return objPerson;
}
}
历史
- 2006 年 9 月 26 日:初始发布