本博客所有文章分類的總目錄:http://www.cnblogs.com/asxinyu/p/4288836.html
Newlife XCode組件相關文章目錄:http://www.cnblogs.com/asxinyu/p/4329747.html
1.前言
最近一個人狂看X組件的源碼,從CommonEntity到XCode,然后XCoder到XCode。感覺自己有很大的進步,視野更加開放,也能夠更加順手的做很多事情。
大石頭在5月份左右的時候,錄制了幾期視頻教程,其中有一期“使用對象容器來解耦業務模塊與管理平台”,對理解X組件很有好處,這期視頻我前后已經聽了4遍,當然每聽一遍都有一些新的發現與體會。今天要總結也是對象容器的一點理解以及為了解決問題,在XCoder源碼中發現的一些東西:接口操作。
2.XCode對象容器介紹
XCode對象容器的使用在XCode后台和Newlife.CommonEntity中有大量的使用,這也是后台很容易擴展的原因之一。只需要繼承相應的實體類(自動注冊優先級高於內部類),而基類中的代碼都是通過接口操作,這樣繼承的類就會優先被系統采用。 管理平台和業務平台通過接口和對象容器聯系起來。對象容器注冊接口的優先級:
1.對象容器注冊優先采用配置文件中指定的接口
2.配置文件里面沒找到之后,會去尋找所有的程序集,找到實現該接口的類,優先級僅次於配置文件。
3.內部實現的類優先級要低,1,2都沒找到,就按默認的實現注冊順序采用。
對象容器的注冊在靜態構造函數中,服務容器基類是泛型基類,這樣只要是繼承基類,然后加一個靜態構造函數,就可以在程序中給實現的接口的類進行注冊。
上面是石頭的一些總結,聽起來可能不容易理解,下面舉一個例子,也算是昨天晚上研究了2個小時的成果吧。
3.XCoder接口操作的實例
XCoder代碼生成器中,可以將數據庫模型保存為XML文件,並可以直接加載XML文件進行模型的修改操作。但是其中有一些不便利。我想做一個直接添加模型的界面,這就涉及到一個問題,如何實例化一個IDataTable對象,查看XCoder的源碼發現了下面的東西:
1 private void btnAddTable_Click(object sender, EventArgs e) 2 { 3 if (Tables == null || Tables.Count < 1) return; 4 5 Type type = Tables[0].GetType(); 6 if (type == null) return; 7 8 IDataTable table = TypeX.CreateInstance(type) as IDataTable; 9 if (table == null) return; 10 11 Tables.Add(table); 12 table.ID = Tables.Count; 13 table.TableName = "NewTable" + table.ID; 14 table.Description = "新建表" + table.ID; 15 16 SetTables(Tables, Tables.Count - 1); 17 }
關鍵的代碼是:Type type = Tables[0].GetType();這里直接獲取當前數據庫中表的類型,然后:
和 IDataTable table = TypeX.CreateInstance(type) as IDataTable; 這里實體化一個接口,再進行賦值。
XCoder內部這樣做,是有優勢的。因為這是導入模型之后才進行的,導入模型的時候,默認實現IDataTable的類已經確定了,因為有對象容器,看XCodeService
1 /// <summary>XCode服務對象提供者</summary> 2 class XCodeService : ServiceContainer<XCodeService> 3 { 4 static XCodeService() 5 { 6 var container = Container; 7 container.Register<IDataTable, XTable>() 8 .AutoRegister<IDataRowEntityAccessorProvider, DataRowEntityAccessorProvider>() 9 .AutoRegister<IEntityPersistence, EntityPersistence>() 10 .AutoRegister<IModelResolver, ModelResolver>(); 11 12 DbFactory.Reg(container); 13 14 EntityAccessorFactory.Reg(container); 15 } 28 #region 使用 29 /// <summary>創建模型數據表</summary> 30 public static IDataTable CreateTable() 31 { 32 return Container.Resolve<IDataTable>(); 33 } 34 }
container.Register<IDataTable, XTable>();就是XCodeService在靜態構造函數中注冊IDataTable的默認實現類XTable,下面的使用方法CreateTable()就是返回一個IDataTable對象,然后在系統的其他地方就可以用XCodeService的這個CreateTable方法創建IDataTable對象了。
那么為什么最上面的代碼中,不這樣創建IDataTable對象呢?這里代碼太多了,只稍微說一下,因為第一段代碼這里已經是導入模型之后了,在導入模型過程中,已經確定了Tables的類型,代碼如下:
1 /// <summary>導入模型</summary> 2 public static List<IDataTable> Import(String xml) 3 { 4 if (String.IsNullOrEmpty(xml)) return null; 5 6 return ModelHelper.FromXml(xml, CreateTable); 7 }
這里的方法是DAL類中的,FromXML方法第二個參數是一個委托,這里傳入的CreateTable就是創建默認的IDataTable實例,看看他的代碼,很簡單,就是內部調用一次XCodeService的方法:
1 /// <summary>建立數據表對象</summary> 2 internal static IDataTable CreateTable() { return XCodeService.CreateTable(); }
到這里應該很清楚了,XCoder中操作對表的操作,都是通過IDataTable,而不設計具體的實現類,比如XTable,在外部程序中,你可以使用自己的Table類,實現IDataTable接口,這樣XCode內部會優先采用外部的實現類。
最后,說一下,這並沒有解決我的問題,在這里大家可能會注意到,XCodeService類是私有的,DAL的CreateTable方法是internal ,這樣外部程序集就沒辦法訪問得到。如果我要在外部程序中直接獲取一個IDataTable 對象,還的確辦不到,除非自己重寫一個IDataTable,但這樣又太麻煩,既然XCode有這樣的功能,不知道大石頭為什么不把DAL的CreateTable設為Public,是不是有什么其他考慮?