Attribute在.NET程式設計中的應用(四) (轉)

amyz發表於2007-11-16
Attribute在.NET程式設計中的應用(四) (轉)[@more@]

Attribute在中的應用(四)

CommandGenerator類的設計

SqlCommandGEnerator類的設計思路就是透過反射得到方法的引數,使用被SqlCommandParameterAttribute標記的引數來裝配一個Command例項。

引用的名稱空間:

//SqlCommandGenerator.cs using System; using System.Reflection; using System.Data; using System.Data.SqlClient; using De = 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 [] 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, SqlType.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的應用,請繼續關注。(待續)

 


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752019/viewspace-982778/,如需轉載,請註明出處,否則將追究法律責任。

相關文章