Attribute在.NET程式設計中的應用(四) (轉)
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/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 設計模式在vue中的應用(四)設計模式Vue
- .NET Attribute在資料校驗上的應用
- socket程式設計在TCP中的應用程式設計TCP
- [譯] 設計 QA 在應用程式設計中的重要性程式設計
- 設計模式及其在spring中的應用(含程式碼)設計模式Spring
- .net core 中的經典設計模式的應用設計模式
- 函數語言程式設計及其在react中的應用函數程式設計React
- union 的概念及在嵌入式程式設計中的應用程式設計
- 設計模式在vue中的應用(一)設計模式Vue
- 設計模式在vue中的應用(七)設計模式Vue
- 設計模式在vue中的應用(六)設計模式Vue
- 設計模式在vue中的應用(三)設計模式Vue
- 設計模式在vue中的應用(二)設計模式Vue
- 設計模式在vue中的應用(五)設計模式Vue
- AOP程式設計之AspectJ介紹及在Android中的應用程式設計Android
- 聯合體在微控制器程式設計中的應用程式設計
- musl libc 與 glibc 在 .NET 應用程式中的相容性
- 設計模式在 TypeScript 中的應用 – 策略模式設計模式TypeScript
- SoIidWorks在鈑金件設計中的應用
- FMEA在車門設計中的應用策略
- FMEA在架構設計中的應用分析架構
- 不走尋常路 設計ASP.NET應用程式的七大絕招(轉)ASP.NET
- .NET 中的併發程式設計程式設計
- 從一個問題中瞭解數學在程式設計中的應用程式設計
- 夏農的“創意思維"在程式設計的應用程式設計
- 在Docker容器中執行ASP.NET MVC應用程式DockerASP.NETMVC
- DFMEA在通訊產品設計中的應用
- Go物件導向程式設計以及在Tendermint/Cosmos-SDK中的應用Go物件程式設計
- web應用servlet中Attribute、Parameter、InitParameter的區別WebServlet
- .NET Web應用中為什麼要使用async/await非同步程式設計WebAI非同步程式設計
- Contravariance 概念在計算機程式設計中的應用計算機程式設計
- IoC在ASP.NET Web API中的應用ASP.NETWebAPI
- .net6+ 在單檔案應用程式中獲取程式集位置
- PDM系統在飼料工程設計中的應用
- 設計模式之--策略模式及其在JDK中的應用設計模式JDK
- UG在鈑金設計與製造中的應用
- AI技術在智慧海報設計中的應用AI
- Java中的非同步程式設計與CompletableFuture應用Java非同步程式設計
- Go函數語言程式設計以及在Tendermint/Cosmos-SDK中的應用Go函數程式設計