Http協議,底層的東西仍是不是特別熟悉,感受要通過沉澱以後才能理解這些東西吧
1.Asp.net生命週期
Asp.net生命週期:
從發起請求開始,到IIS進行處理的所有過程,而後再到獲取結果
當請求一個*.aspx文件的時候,這個請求會被inetinfo.exe進程截獲,它判斷文件的後綴(aspx)以後,將這個請求轉交給ASPNET_ISAPI.dll,ASPNET_ISAPI.dll會經過http管道(Http PipeLine)將請求發送給ASPNET_WP.exe進程,在ASPNET_WP.exe進程中經過HttpRuntime來處理這個請求,處理完畢將結果返回客戶端。 inetinfo.exe進程:是www服務的進程,IIS服務和ASPNET_ISAPI.DLL都寄存在此進程中。 ASPNET_ISAPI.DLL:是處理.aspx文件的win32組件。其實IIS服務器是隻能識別.html文件的,當IIS服務器發現被請求的文件是.aspx文件時,IIS服務器將其交給aspnet_isapi.dll來處理。 aspnet_wp.exe進程:ASP.NET框架進程,提供.net運行的託管環境,.net的CLR(公共語言運行時)就是寄存在此進程中。
ASP.NET Framework處理一個Http Request的流程: HttpRequest-->inetinfo.exe-->ASPNET_ISAPI.dll-->ASPNET_WP.exe-->HttpRuntime-->HttpApplication Factory-->HttpApplication-->HttpModule-->HttpHandler Factory-->HttpHandler-->HttpHandler.ProcessRequest()
ASP.NET請求處理過程是基於管道模型的,這個管道模型是由多個HttpModule和HttpHandler組成,ASP.NET把http請求依次傳遞給管道中各個HttpModule,最終被HttpHandler處理,處理完成後,再次通過管道中的HTTP模塊,把結果返回給客戶端。咱們能夠在每一個HttpModule中均可以干預請求的處理過程。
2.Htpp協議的生命週期
這個感受要後續繼續加深理解以後再進行補充吧,目前就拿別人的思路來解答這個過程
1.輸入url,瀏覽器DNS解析域名,獲取ip
2.三次握手,創建tcp連接
3.向服務端發送http請求
4.服務端處理請求並響應
5.瀏覽器渲染HTML
6在渲染的過程當中繼續加載css,js,圖片,音頻,視頻文件
7 呈現給用戶
託管代碼與非託管代碼的區別
實際上是知道這個東西,可是不知道專業術語竟然叫這個,我覺得是Azure雲託管,好吧,開個玩笑
不止C#,java也是託管代碼啊,重點,重點,重點!!!
1.簡單的說,就是代碼被編譯成MSIL後在.net的Framework下運行,同操做系統底層的交互都交給framework去作。所謂非託管代碼就是脫離了Framework的管制,
直接同底層API打交道,本身管理本身的內存和安全機制等東西。而託管代碼就無論這些,全都由Framework去完成
2.「程序」通常都是在對操做系統進行直接或者間接的操做
「託管程序」是須要經過訪問公共語言運行時(cls)才能訪問操做系統的程序
而「非託管程序」不用經過訪問公共語言運行時(cls)能夠直接訪問操做系統的程序
3.vb.net,C#等寫的程序是託管程序,VC++能夠寫託管程序,若是用到了內存管理,則只能編譯爲非託管程序這些東西MSDN都有描述
經過IEnumerable接口遍歷數據
使用IEnumerable接口遍歷數據,這在項目中會常常的用到,這個類型呢主要是一個枚舉器。
1.首先須要讓該類型實現一個名字叫IEnumerable的接口,實現該接口的主要目的是爲了讓當前類型中增長一個名字叫GetEnumerator()的方法。
public class Person : IEnumerable { private string[] Friends = new string[] { "張三", "李四", "王五", "趙六" }; public string Name { get; set; } public int Age { get; set; } public string Email { get; set; } #region IEnumerable 成員 //這個方法的做用就是返回一個「枚舉器」 public IEnumerator GetEnumerator() { return new PersonEnumerator(this.Friends); } #endregion }
2.但願一個類型被枚舉遍歷,就是要實現一個枚舉器方法
public class PersonEnumerator : IEnumerator { public PersonEnumerator(string[] fs) { _friends = fs; } private string[] _friends; //通常下標都是一開始指向了第一條的前一條。第一條是0 private int index = -1; #region IEnumerator 成員 public object Current { get { if (index >= 0 && index < _friends.Length) //下標有範圍 { return _friends[index]; } else { throw new IndexOutOfRangeException(); } } } public bool MoveNext() { if (index + 1 < _friends.Length) //下標有範圍 { index++; return true; } return false; } public void Reset() { index = -1; } #endregion }
3.而後進行遍歷,這裏呢能夠調用本身封裝的MoveNext方法去找數組元素
Person p = new Person(); IEnumerator etor = p.GetEnumerator(); while (etor.MoveNext()) { Console.WriteLine(etor.Current.ToString()); }
也能夠直接使用foreach,並且主要是由於是枚舉元素,相似與數組,list等等之類的,均可以使用Lambda表達式來進行數據的處理
Person p = new Person(); foreach (string item in p) { Console.WriteLine(item); } Console.WriteLine("ok");
4.輸出的結果以下:
依賴注入與控制反轉
反正這個概念我通常都是不去記得,首先看一下什麼是依賴:
有一個類是Animal,而後我定義了一個BlackCat類,類裏面有一個BlackCat方法,那麼這裏的BlackCat就依賴Animal
public class BlackCat { public BlackCat(Animal Cat) { Cry(); } }
BlackCat類實例化的時候須要一個Animal的對象做爲構造函數的參數,那麼BlackCat就依賴Animal,這就叫依賴。
固然,不用構造函數的方式,在BlackCat類內部去new一個Animal,也是依賴;固然注入的話,就像是你寫了一個類,而後
經過IOC框架,把這個類注入到其餘類中,這就是注入
控制反轉的意思就好理解了,就好比我定義了一個類,類裏面有一個方法,而後我如今要把這個方法的控制權交給別人來使用,這就是控制反轉。
在編寫代碼的時候,咱們須要把一些接口編寫成通用的道理就在這裏了,便於作到代碼複用
下面即以貓的例子來進行解說控制反轉
1.先定義一個動物類
using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace IOC { class Animal { public void Cry() { Console.Write("動物喊叫"); } } }
2.定義一個貓的類
using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace IOC { class Cat:Animal { public void Cry() { Console.WriteLine("動物喊叫"); } } }
3.我用實例化一個動物類,而後查看結果
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace IOC { class Program { static void Main(string[] args) { Animal A = new Cat(); A.Cry(); Console.ReadLine(); } } }
4.能夠看到我用子類能夠替換掉父類,也能夠用父類替換掉子類,其實並無太大的影響
Animal A = new Cat();
能夠看見輸出結果以下
C#多線程——優先級
在個人公司這裏,由於要跟不少特殊的設備打交道,因此會用到多線程的東西,那麼咱們在進行多線程處理的時候,怎麼去設置優先級
我這裏用聽歌和下載小說作了個例子,咱們用電腦的時候確定是能夠邊聽歌邊下載小說的,那麼這就須要並行,有個問題就是我想優先聽
歌,下載小說對我來講不是那麼急的話我就能夠對兩個事情進行優先級的管控。
線程裏有個屬性Priority能夠用來設置優先級,我設置線程1的優先級高於線程2的優先級,那麼線程1就會比線程2多運行一段時間,這個是人眼觀察不出來的
運行速度,CPU運行速度可不是能用人眼查看的
bool b = true; int i=0, j=0; string Song = ""; string Download = ""; Thread Thread1=new Thread(() => { while (b) { Song="一百萬個可能"; i++; } }) { Name = "Thread1", Priority = ThreadPriority.Highest }; Thread Thread2=new Thread(() => { while (b) { Download = "小說三體"; j++; } }) { Name = "Thread2", Priority = ThreadPriority.Lowest }; Thread1.Start(); Thread2.Start(); Thread.Sleep(1000); b = false; Console.WriteLine("Song: {0}, Download: {1}", Song, Download); Console.WriteLine("歌曲的優先級:{0}",i); Console.WriteLine("下載的優先級:{0}",j); Console.ReadLine();
這裏咱們看一下執行結果
從結果中能夠看到,優先級高的線程獲得運行的次數比優先級低的線程多,但即便是最低優先級的線程都有很大的機會來執行。
AutoFac容器初步
轉載請註明出處,AutoFac:最流行的依賴注入和IOC框架,輕量且高性能,對項目代碼幾乎無任何侵入性。
那麼咱們怎麼來使用這樣一個框架呢
一、在引用項右擊,選擇Nuget管理,這裏咱們要導入兩個包
一個是AutoFac包,另一個就是Autofac ASP.NET MVC5 Intergration
在webapi裏面使用的話咱們須要添加一個Autofac ASP.NET Web API2.2 Intergration 才能夠。
2.Global.asax.cs屬性注入,配置IOC容器,我這裏配置的是通用的以I開頭的Repository(倉庫類)
#region autofac IOC容器配置 var builder = new ContainerBuilder(); //註冊全部的controller builder.RegisterControllers(typeof(MvcApplication).Assembly).PropertiesAutowired(); //註冊全部模塊module builder.RegisterAssemblyModules(Assembly.GetExecutingAssembly()); var assemblys = BuildManager.GetReferencedAssemblies().Cast<Assembly>().ToArray(); //註冊全部繼承IDependency接口的類 builder.RegisterAssemblyTypes(assemblys) .Where(type => typeof(IDependency).IsAssignableFrom(type) && !type.IsAbstract); //註冊服務,全部IxxxxRepository=>xxxxRepository builder.RegisterAssemblyTypes(assemblys).Where(t => t.Name.EndsWith("Repository") && !t.Name.StartsWith("I")).AsImplementedInterfaces(); var container = builder.Build(); BaseInfo._container = container; DependencyResolver.SetResolver(new AutofacDependencyResolver(container)); #endregion
3.新建實體基類以及實體類,也就是建立數據模型
base類:
public class BaseEntity { [NotMapped] [PropertyModelBinder("start")] public int pageIndex { get; set; } [NotMapped] [PropertyModelBinder("length")] public int pageSize { get; set; } [NotMapped] public string draw { get; set; } [NotMapped] public List<Orderby> order { get; set; } [NotMapped] public List<Datacolumn> columns { get; set; } } public class Orderby { public string column { get; set; } public string dir { get; set; } } public class Datacolumn { public string data { get; set; } public string name { get; set; } public bool searchable { get; set; } public bool orderable { get; set; } }
實體類:
public class User : BaseEntity { public User() { RoleList = new List<Role>(); MessageList = new List<UserMappingMessage>(); } public int UserID { get; set; } public string UserName { get; set; } public string UserPassword {get;set;} public string UserReallyname {get;set;} public string HeadPortrait { get; set; } public string MobilePhone { get; set; } public string Email { get; set; } public int DepartmentID {get;set;} public bool IsEnable {get;set;} public DateTime CreateTime {get;set;} public DateTime? UpdateTime {get;set;} public string Remark { get; set; } public ICollection<Role> RoleList { get; set; } //接收消息列表 public ICollection<UserMappingMessage> MessageList { get; set; } public Dictionary Department { get; set; } //發送消息列表 public List<Message> Messages { get; set; } }
4.建立倉儲接口,由於我在配置Global屬性時,已經說明了我要注入全部以 「I」 開頭的接口,那麼我就把這個用戶的接口給定義爲IUserRepository
固然,不一樣的實體類所須要的倉儲接口也不同,這裏根據本身的實際需求去寫須要的方法類,接口嘛,就不要在這裏具體實現你的方法了
public interface IUserRepository { Tuple<int,List<User>> GetList(User model); List<User> GetUserInfos(); User GetSingle(User model); User GetbyID(int userID); void AddUser(User model); void ModifyUser(User model); void DeleteUser(User model); void SetUserInfoRole(int userID, List<int> roleIDList); List<AutoUserDo> GetUserInfobyName(string value); void ResetUserPWDbyID(int id); }
5.咱們定義一個實現接口的類,而後把接口的方法給實現,這裏面就是對數據實體進行操做了
public class UserRepository : IUserRepository { public Tuple<int, List<User>> GetList(User model) { using (UnitOfWork dal=BaseInfo._container.Resolve<UnitOfWork>()) { var SysUserRepository = dal.GetRepository<User>(); var conditions = ExpandHelper.True<User>(); if (!string.IsNullOrEmpty(model.UserName)) conditions = conditions.And(a => a.UserName.Contains(model.UserName)); if (!string.IsNullOrEmpty(model.UserReallyname)) conditions = conditions.And(a => a.UserReallyname.Contains(model.UserReallyname)); if (model.DepartmentID > 0) conditions = conditions.And(a => a.DepartmentID == model.DepartmentID); var templist = SysUserRepository.Get(filter: conditions, includeProperties: "RoleList"); var count = templist.Count(); if (model.order != null&&model.order.Count()>0) { foreach (var item in model.order) { var column = model.columns.ElementAt(int.Parse(item.column)); templist = templist.OrderSort(column.data, item.dir); } } var result = templist.PageBy(model.pageIndex, model.pageSize).ToList(); return new Tuple<int, List<User>>(count, result); } } public User GetSingle(User model) { using(UnitOfWork dal=BaseInfo._container.Resolve<UnitOfWork>()){ var conditions = ExpandHelper.True<User>(); if (!string.IsNullOrEmpty(model.UserName)) conditions = conditions.And( a => a.UserName == model.UserName || a.MobilePhone == model.UserName); if (!string.IsNullOrEmpty(model.MobilePhone)) conditions = conditions.And(a => a.MobilePhone == model.MobilePhone); var result = dal.GetRepository<User>().Get(conditions).FirstOrDefault(); return result; } } public User GetbyID(int userID) { using (UnitOfWork dal = BaseInfo._container.Resolve<UnitOfWork>()) { // var result = dal.GetRepository<User>().Get(filter: a => a.UserID == userID, includeProperties: "RoleList.MenuList,RoleList.rbList").AsNoTracking().FirstOrDefault(); var result = dal.GetRepository<User>().Get(filter: a => a.UserID == userID,includeProperties: "RoleList").FirstOrDefault(); foreach (var item in result.RoleList) { var role=dal.GetRepository<Role>().Get(a=>a.RoleID==item.RoleID,includeProperties:"MenuList,rbList").FirstOrDefault(); item.MenuList = role.MenuList; item.rbList = role.rbList; } return result; } } public void AddUser(User model) { using (UnitOfWork dal = BaseInfo._container.Resolve<UnitOfWork>()) { dal.GetRepository<User>().Insert(model); dal.Save(); } } public void ModifyUser(User model) { using (UnitOfWork dal = BaseInfo._container.Resolve<UnitOfWork>()) { dal.GetRepository<User>().UpdateSup(model, new List<string>() { "IsEnable", "CreateTime" }, false); dal.Save(); } } public void DeleteUser(User model) { using (UnitOfWork dal = BaseInfo._container.Resolve<UnitOfWork>()) { var sysUserRepository= dal.GetRepository<User>(); var Usermodel = sysUserRepository.GetByID(model.UserID); Usermodel.IsEnable=Usermodel.IsEnable?false:true; sysUserRepository.UpdateSup(Usermodel, new List<string>() { "IsEnable" }); dal.Save(); } } /// <summary> /// 添加用戶角色信息,先刪除原有數據,在添加到數據庫 /// </summary> /// <param name="userID"></param> /// <param name="roleIDList"></param> /// <returns></returns> public void SetUserInfoRole(int userID, List<int> roleIDList) { using (UnitOfWork dal = BaseInfo._container.Resolve<UnitOfWork>()) { var sysUserRepository = dal.GetRepository<User>(); var roleRepository = dal.GetRepository<Role>(); var UserModel = GetbyID(userID); var roleList = UserModel.RoleList.ToList(); roleList.ForEach(m => { var userModel = sysUserRepository.Get(filter: a => a.UserID == userID, includeProperties: "RoleList").FirstOrDefault(); var roleModel = roleRepository.GetByID(m.RoleID); userModel.RoleList.Remove(roleModel); }); roleIDList.ForEach(m => { var userModel = sysUserRepository.GetByID(userID); var roleModel = roleRepository.GetByID(m); userModel.RoleList.Add(roleModel); }); dal.Save(); } } public List<AutoUserDo> GetUserInfobyName(string value) { Mapper.Initialize(a => { a.CreateMap<User, AutoUserDo>() .ForMember(au => au.id, op => { op.MapFrom(user => user.UserID); }) .ForMember(au => au.text, op => { op.MapFrom(user => user.UserReallyname); }) .ForMember(au => au.department, op => { op.MapFrom(user => user.Department.DicValue); }); a.CreateMap<Role, roleinfo>(); }); using (var dal = BaseInfo._container.Resolve<UnitOfWork>()) { return dal.GetRepository<User>() .Get(a => a.UserReallyname.Contains(value) || a.MobilePhone == value, includeProperties: "Department,Role").ProjectToQueryable<AutoUserDo>().ToList(); } } public void ResetUserPWDbyID(int id) { using (var dal = BaseInfo._container.Resolve<UnitOfWork>()) { var repository = dal.GetRepository<User>(); var usermodel = new User() { UserID = id, UserPassword = "123456" }; repository.UpdateSup(usermodel, new List<string>() { "UserPassword" }); dal.Save(); } } public List<User> GetUserInfos() { using (var dal = BaseInfo._container.Resolve<UnitOfWork>()) { return dal.GetRepository<User>().Get().ToList(); } } }
6.而後咱們就能夠在MVC的控制器裏面去調用這些方法來實現咱們所想要的功能了,我這裏只展現一個方法
public void SendEmailAsync(Message model) { Task.Run(() => { try { var reclist = string.Empty; foreach (var item in model.RecUser.Split(',')) { var userinfo = this.UserRepository.GetbyID(int.Parse(item)); //這裏就調用了實現接口的那個類的方法,去驗證用戶的ID if (!string.IsNullOrEmpty(userinfo.Email)) { reclist += userinfo.Email + ","; } } if (!string.IsNullOrEmpty(reclist)) { reclist = reclist.Substring(0, reclist.Length - 1); EmailHelper email = new EmailHelper(reclist, model.MessageTitle, model.MessageText); email.Send(); } model.SendEmailState = 2; this.MessageServer.SetSendState(model); }catch(Exception ex){ new LogHelper().LogError("發送郵件異常" + ex); model.SendEmailState = 3; this.MessageServer.SetSendState(model); } }); }
那麼整個流程就是這樣,看着別人寫的那些博客裏面的流程不是那麼的全面,我這裏就詳細的把AutoFac的整個流程給梳理出來了,有不對的地方請及時指出
後面我會詳細說明一下Unity IOC框架是如何使用的,這裏我就再也不敘述了
下面是兩篇比較好的博文,我以爲比較有參考意義的,能夠看一下,喜歡我發佈的內容的能夠關注我,後面還會有其餘的乾貨和內容進行分享
.NET領域最爲流行的IOC框架之一Autofac:https://www.cnblogs.com/yinrq/p/5381492.html
.NET Unity IOC框架使用實例:https://blog.csdn.net/chen_peng7/article/details/54896449
C#特性詳解
特性(attribute)是被指定給某一聲明的一則附加的聲明性信息。
在C#中,有一個小的預約義特性集合。在學習如何創建咱們本身的定製特性(custom attributes)以前,咱們先來看看在咱們的代碼中如何使用預約義特性。
1 using System; 2 public class AnyClass 3 { 4 [Obsolete("Don't use Old method, use New method", true)] 5 static void Old( ) { } 6 static void New( ) { } 7 public static void Main( ) 8 { 9 Old( ); 10 } 11 }
咱們先來看一下上面這個例子,在這個例子中咱們使用了Obsolete特性,它標記了一個不該該再被使用的程序實體。第一個參數是一個字符串,它解釋了爲何該實體是過期的以及應該用什麼實體來代替它。實際上,你能夠在這裏寫任何文本。第二個參數告訴編譯器應該把使用這個過期的程序實體看成一種錯誤。它的默認值是false,也就是說編譯器對此會產生一個警告。
當咱們嘗試編譯上面這段程序的時候,咱們將會獲得一個錯誤:
AnyClass.Old()' is obsolete: 'Don't use Old method, use New method'
開發定製特性(custom attributes)
如今讓咱們來看看如何開發咱們本身的特性。
首先咱們要從System.Attribute派生出咱們本身的特性類(一個從System.Attribute抽象類繼承而來的類,無論是直接仍是間接繼承,都會成爲一個特性類。特性類的聲明定義了一種能夠被放置在聲明之上新的特性)。
1 using System; 2 public class HelpAttribute : Attribute 3 { 4 }
無論你是否相信,咱們已經創建了一個定製特性,如今咱們能夠用它來裝飾現有的類就好像上面咱們使用Obsolete attribute同樣。
1 [Help()] 2 public class AnyClass 3 { 4 }
注意:對一個特性類名使用Attribute後綴是一個慣例。然而,當咱們把特性添加到一個程序實體,是否包括 Attribute後綴是咱們的自由。編譯器會首先在System.Attribute的派生類中查找被添加的特性類。若是沒有找到,那麼編譯器會添加 Attribute後綴繼續查找。
到目前爲止,這個特性尚未起到什麼做用。下面咱們來添加些東西給它使它更有用些。
1 using System; 2 public class HelpAttribute : Attribute 3 { 4 public HelpAttribute(String Descrition_in) 5 { 6 this.description = Description_in; 7 } 8 protected String description; 9 public String Description 10 { 11 get 12 { 13 return this.description; 14 } 15 } 16 } 17 [Help("this is a do-nothing class")] 18 public class AnyClass 19 { 20 }
在上面的例子中,咱們給HelpAttribute特性類添加了一個屬性而且在後續的部分中咱們會在運行時環境中查尋它。
定義或控制特性的使用
AttributeUsage類是另一個預約義特性類,它幫助咱們控制咱們本身的定製特性的使用。它描述了一個定製特性如和被使用。
AttributeUsage有三個屬性,咱們能夠把它放置在定製屬性前面。第一個屬性是:
ValidOn
經過這個屬性,咱們可以定義定製特性應該在何種程序實體前放置。一個屬性能夠被放置的全部程序實體在AttributeTargets enumerator中列出。經過OR操做咱們能夠把若干個AttributeTargets值組合起來。
AllowMultiple
這個屬性標記了咱們的定製特性可否被重複放置在同一個程序實體前屢次。
Inherited
咱們可使用這個屬性來控制定製特性的繼承規則。它標記了咱們的特性可否被繼承。
下面讓咱們來作一些實際的東西。咱們將會在剛纔的Help特性前放置AttributeUsage特性以期待在它的幫助下控制Help特性的使用。
1 using System; 2 [AttributeUsage(AttributeTargets.Class), AllowMultiple = false, 3 Inherited = false ] 4 public class HelpAttribute : Attribute 5 { 6 public HelpAttribute(String Description_in) 7 { 8 this.description = Description_in; 9 } 10 protected String description; 11 public String Description 12 { 13 get 14 { 15 return this.description; 16 } 17 } 18 }
先讓咱們來看一下AttributeTargets.Class。它規定了Help特性只能被放在class的前面。這也就意味着下面的代碼將會產生錯誤:
1 [Help("this is a do-nothing class")] 2 public class AnyClass 3 { 4 [Help("this is a do-nothing method")] //error 5 public void AnyMethod() 6 { 7 } 8 }
編譯器報告錯誤以下:
AnyClass.cs: Attribute 'Help' is not valid on this declaration type.
It is valid on 'class' declarations only.
咱們可使用AttributeTargets.All來容許Help特性被放置在任何程序實體前。可能的值是:
Assembly,Module,Class,Struct,Enum,Constructor,Method,Property,Field,Event,Interface,Parameter,Delegate
All = Assembly | Module | Class | Struct | Enum | Constructor | Method | Property | Field | Event | Interface | Parameter | Delegate
ClassMembers = Class | Struct | Enum | Constructor | Method | Property | Field | Event | Delegate | Interface
下面考慮一下AllowMultiple = false。它規定了特性不能被重複放置屢次。
1 [Help("this is a do-nothing class")] 2 [Help("it contains a do-nothing method")] 3 public class AnyClass 4 { 5 [Help("this is a do-nothing method")] //error 6 public void AnyMethod() 7 { 8 } 9 }
它產生了一個編譯期錯誤。
AnyClass.cs: Duplicate 'Help' attribute
Ok,如今咱們來討論一下最後的這個屬性。Inherited, 代表當特性被放置在一個基類上時,它可否被派生類所繼承。
1 [Help("BaseClass")] 2 public class Base 3 { 4 } 5 public class Derive : Base 6 { 7 }
這裏會有四種可能的組合:
1 [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false ] 2 [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = false ] 3 [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true ] 4 [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true ]
第一種狀況:
若是咱們查詢(Query)(稍後咱們會看到如何在運行期查詢一個類的特性)Derive類,咱們將會發現Help特性並不存在,由於inherited屬性被設置爲false。
第二種狀況:
和第一種狀況相同,由於inherited也被設置爲false。
第三種狀況:
爲了解釋第三種和第四種狀況,咱們先來給派生類添加點代碼:
1 [Help("BaseClass")] 2 public class Base 3 { 4 } 5 [Help("DeriveClass")] 6 public class Derive : Base 7 { 8 }
如今咱們來查詢一下Help特性,咱們只能獲得派生類的屬性,由於inherited被設置爲true,可是AllowMultiple卻被設置爲false。所以基類的Help特性被派生類Help特性覆蓋了。
第四種狀況:
在這裏,咱們將會發現派生類既有基類的Help特性,也有本身的Help特性,由於AllowMultiple被設置爲true。
定義或控制特性的使用AttributeUsage類是另一個預約義特性類,它幫助咱們控制咱們本身的定製特性的使用。它描述了一個定製特性如何被使用。
屬性和特性的區別能夠參考一下: http://developer.51cto.com/art/200908/147097.htm
本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/Foxalien/archive/2009/12/05/4946672.aspx
C#特性詳解
特性(attribute)是被指定給某一聲明的一則附加的聲明性信息。
在C#中,有一個小的預約義特性集合。在學習如何創建咱們本身的定製特性(custom attributes)以前,咱們先來看看在咱們的代碼中如何使用預約義特性。
1 using System; 2 public class AnyClass 3 { 4 [Obsolete("Don't use Old method, use New method", true)] 5 static void Old( ) { } 6 static void New( ) { } 7 public static void Main( ) 8 { 9 Old( ); 10 } 11 }
咱們先來看一下上面這個例子,在這個例子中咱們使用了Obsolete特性,它標記了一個不該該再被使用的程序實體。第一個參數是一個字符串,它解釋了爲何該實體是過期的以及應該用什麼實體來代替它。實際上,你能夠在這裏寫任何文本。第二個參數告訴編譯器應該把使用這個過期的程序實體看成一種錯誤。它的默認值是false,也就是說編譯器對此會產生一個警告。
當咱們嘗試編譯上面這段程序的時候,咱們將會獲得一個錯誤:
AnyClass.Old()' is obsolete: 'Don't use Old method, use New method'
開發定製特性(custom attributes)
如今讓咱們來看看如何開發咱們本身的特性。
首先咱們要從System.Attribute派生出咱們本身的特性類(一個從System.Attribute抽象類繼承而來的類,無論是直接仍是間接繼承,都會成爲一個特性類。特性類的聲明定義了一種能夠被放置在聲明之上新的特性)。
1 using System; 2 public class HelpAttribute : Attribute 3 { 4 }
無論你是否相信,咱們已經創建了一個定製特性,如今咱們能夠用它來裝飾現有的類就好像上面咱們使用Obsolete attribute同樣。
1 [Help()] 2 public class AnyClass 3 { 4 }
注意:對一個特性類名使用Attribute後綴是一個慣例。然而,當咱們把特性添加到一個程序實體,是否包括 Attribute後綴是咱們的自由。編譯器會首先在System.Attribute的派生類中查找被添加的特性類。若是沒有找到,那麼編譯器會添加 Attribute後綴繼續查找。
到目前爲止,這個特性尚未起到什麼做用。下面咱們來添加些東西給它使它更有用些。
1 using System; 2 public class HelpAttribute : Attribute 3 { 4 public HelpAttribute(String Descrition_in) 5 { 6 this.description = Description_in; 7 } 8 protected String description; 9 public String Description 10 { 11 get 12 { 13 return this.description; 14 } 15 } 16 } 17 [Help("this is a do-nothing class")] 18 public class AnyClass 19 { 20 }
在上面的例子中,咱們給HelpAttribute特性類添加了一個屬性而且在後續的部分中咱們會在運行時環境中查尋它。
定義或控制特性的使用
AttributeUsage類是另一個預約義特性類,它幫助咱們控制咱們本身的定製特性的使用。它描述了一個定製特性如和被使用。
AttributeUsage有三個屬性,咱們能夠把它放置在定製屬性前面。第一個屬性是:
ValidOn
經過這個屬性,咱們可以定義定製特性應該在何種程序實體前放置。一個屬性能夠被放置的全部程序實體在AttributeTargets enumerator中列出。經過OR操做咱們能夠把若干個AttributeTargets值組合起來。
AllowMultiple
這個屬性標記了咱們的定製特性可否被重複放置在同一個程序實體前屢次。
Inherited
咱們可使用這個屬性來控制定製特性的繼承規則。它標記了咱們的特性可否被繼承。
下面讓咱們來作一些實際的東西。咱們將會在剛纔的Help特性前放置AttributeUsage特性以期待在它的幫助下控制Help特性的使用。
1 using System; 2 [AttributeUsage(AttributeTargets.Class), AllowMultiple = false, 3 Inherited = false ] 4 public class HelpAttribute : Attribute 5 { 6 public HelpAttribute(String Description_in) 7 { 8 this.description = Description_in; 9 } 10 protected String description; 11 public String Description 12 { 13 get 14 { 15 return this.description; 16 } 17 } 18 }
先讓咱們來看一下AttributeTargets.Class。它規定了Help特性只能被放在class的前面。這也就意味着下面的代碼將會產生錯誤:
1 [Help("this is a do-nothing class")] 2 public class AnyClass 3 { 4 [Help("this is a do-nothing method")] //error 5 public void AnyMethod() 6 { 7 } 8 }
編譯器報告錯誤以下:
AnyClass.cs: Attribute 'Help' is not valid on this declaration type.
It is valid on 'class' declarations only.
咱們可使用AttributeTargets.All來容許Help特性被放置在任何程序實體前。可能的值是:
Assembly,Module,Class,Struct,Enum,Constructor,Method,Property,Field,Event,Interface,Parameter,Delegate
All = Assembly | Module | Class | Struct | Enum | Constructor | Method | Property | Field | Event | Interface | Parameter | Delegate
ClassMembers = Class | Struct | Enum | Constructor | Method | Property | Field | Event | Delegate | Interface
下面考慮一下AllowMultiple = false。它規定了特性不能被重複放置屢次。
1 [Help("this is a do-nothing class")] 2 [Help("it contains a do-nothing method")] 3 public class AnyClass 4 { 5 [Help("this is a do-nothing method")] //error 6 public void AnyMethod() 7 { 8 } 9 }
它產生了一個編譯期錯誤。
AnyClass.cs: Duplicate 'Help' attribute
Ok,如今咱們來討論一下最後的這個屬性。Inherited, 代表當特性被放置在一個基類上時,它可否被派生類所繼承。
1 [Help("BaseClass")] 2 public class Base 3 { 4 } 5 public class Derive : Base 6 { 7 }
這裏會有四種可能的組合:
1 [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false ] 2 [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = false ] 3 [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true ] 4 [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true ]
第一種狀況:
若是咱們查詢(Query)(稍後咱們會看到如何在運行期查詢一個類的特性)Derive類,咱們將會發現Help特性並不存在,由於inherited屬性被設置爲false。
第二種狀況:
和第一種狀況相同,由於inherited也被設置爲false。
第三種狀況:
爲了解釋第三種和第四種狀況,咱們先來給派生類添加點代碼:
1 [Help("BaseClass")] 2 public class Base 3 { 4 } 5 [Help("DeriveClass")] 6 public class Derive : Base 7 { 8 }
如今咱們來查詢一下Help特性,咱們只能獲得派生類的屬性,由於inherited被設置爲true,可是AllowMultiple卻被設置爲false。所以基類的Help特性被派生類Help特性覆蓋了。
第四種狀況:
在這裏,咱們將會發現派生類既有基類的Help特性,也有本身的Help特性,由於AllowMultiple被設置爲true。
定義或控制特性的使用AttributeUsage類是另一個預約義特性類,它幫助咱們控制咱們本身的定製特性的使用。它描述了一個定製特性如何被使用。
屬性和特性的區別能夠參考一下: http://developer.51cto.com/art/200908/147097.htm
本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/Foxalien/archive/2009/12/05/4946672.aspx
WPF 可觸摸移動的ScrollViewer控件
ListBox支持觸摸滑動,而ScrollViewer默認不支持。
ScrollViewer如須要添加上下/左右觸摸移動,須要在Touch事件中處理。
處理以下:封裝成一個用戶控件
- TouchDown事件中記錄起始點,並添加對TouchMove事件的監聽
- TouchUp事件中註銷TouchMove事件的監聽
- 在TouchMove事件中,處理移動的偏移量。起始位置減去偏移量,即爲當前滾動條的位置。
注:ScrollViewer滾動到指定位置(指定位置=起始位置-移動的偏移量,滾動方向和手勢方向相反)
1 /// <summary> 2 /// 可觸摸滾動的ScrollViewer控件 3 /// </summary> 4 public class TouchableScrollViewer : ScrollViewer 5 { 6 //觸摸點的座標 7 Point _startPosition; 8 //滾動條當前位置 9 double _startVerticalOffset; 10 double _startHorizontalOffset; 11 public TouchableScrollViewer() 12 { 13 TouchDown += TouchableScrollViewer_TouchDown; 14 15 TouchUp += TouchableScrollViewer_TouchUp; 16 } 17 private void TouchableScrollViewer_TouchDown(object sender, TouchEventArgs e) 18 { 19 //添加觸摸移動監聽 20 TouchMove -= TouchableScrollViewer_TouchMove; 21 TouchMove += TouchableScrollViewer_TouchMove; 22 23 //獲取ScrollViewer滾動條當前位置 24 _startVerticalOffset = VerticalOffset; 25 _startHorizontalOffset = HorizontalOffset; 26 27 //獲取相對於ScrollViewer的觸摸點位置 28 TouchPoint point = e.GetTouchPoint(this); 29 _startPosition = point.Position; 30 } 31 32 private void TouchableScrollViewer_TouchUp(object sender, TouchEventArgs e) 33 { 34 //註銷觸摸移動監聽 35 TouchMove -= TouchableScrollViewer_TouchMove; 36 } 37 38 private void TouchableScrollViewer_TouchMove(object sender, TouchEventArgs e) 39 { 40 //獲取相對於ScrollViewer的觸摸點位置 41 TouchPoint endPoint = e.GetTouchPoint(this); 42 //計算相對位置 43 double diffOffsetY = endPoint.Position.Y - _startPosition.Y; 44 double diffOffsetX = endPoint.Position.X - _startPosition.X; 45 46 //ScrollViewer滾動到指定位置(指定位置=起始位置-移動的偏移量,滾動方向和手勢方向相反) 47 ScrollToVerticalOffset(_startVerticalOffset - diffOffsetY); 48 ScrollToHorizontalOffset(_startHorizontalOffset - diffOffsetX); 49 } 50 }
Demo下載
.NET(C#)能開發出什麼樣的APP?盤點那些經過Smobiler開發的移動應用
.NET程序員必定最熟悉所見即所得式開發,熟悉的Visual Studio開發界面,熟悉的C#代碼。
Smobiler也是由於具有這樣的特性,使開發人員,能夠在VisualStudio上,像開發WinForm同樣拖拉控件,讓許多人在開發APP時,再次回到所見即所得的開發方式中去。
Smobiler的快速開發,讓Amanda看到了程序員們分享的各式各樣的應用。
一
來自程序員的分享
👆產線物料管理類的應用
實時監控產線物料狀況
社區物業管理類的應用👇
方便社區居民在線查詢、繳費
👆公益社區類的應用
爲公益熱心者提供一個線上社區
企業內部OA管理應用👇
請假、工做流、報銷等功能
以上截圖均來自Smobiler技術開發羣用戶的分享
二
一千個應用有一千種界面
在「家庭小祕」沒出現以前,咱們也是想不到會有用戶願意在UI上投入資源,作出出這樣簡潔好看的界面。
家庭小祕APP
畢竟咱們見到更多的是企業類應用,對UI界面要求沒那麼高,功能至上。
好比這個花了十來天作的企業內部管理應用:
一款爲練手而作的APP
這只是練手之做,我們先把後端的業務代碼跑通,UI設計什麼的,正式項目裏,交給專業的設計師會更省事。
專業的和業餘雖然都能把意思表達出來,但區別就跟下面這張圖同樣:
三
官方推出的三款開源APP
Smobiler官方也前後推出了三款開源的應用,應用的源代碼已經託管至GitHub,這三款應用分別是
SmoONE:開源的移動OA應用
包含了GPS定位、IM等功能
SmoSEC:開源的資產管理移動應用
包含了條碼掃描、RFID掃描等功能
SmoWMS:開源的倉庫管理移動應用
包含倉庫管理中的基本核心功能,固然倉庫管理中的條碼掃描、RFID掃描等也是不可少的
(文末有這三款應用源代碼的獲取方式。)
重點是,這三款應用的代碼,都是
免費!開源的!
你能夠把源碼下載下來,而後根據項目的需求,進行二次開發。好比這樣
左圖是SmoONE的界面,右圖是用戶在SmoONE源碼基礎上的修改
好比這樣:
左圖是SmoWMS的界面,右圖是用戶在SmoWMS源碼基礎上的修改
這樣的界面從零作起,總共只分三步,大概須要兩分鐘吧:
第一步:拖拉控件
第二步:設置title和toolbar屬性
第三步:設置iconmenuview屬性和啓動程序
最後作什麼樣的APP,徹底看項目須要,和程序員的心情,以及……客戶是否介意你依照本身的喜愛作出來的界面。
作項目嘛,最重要的是效率;敲代碼嘛,最重要的就是開心。
四
三款開源項目的獲取方式
在GitHub上搜索
「SmoONE」、「SmoSEC」、「SmoWMS」
即可找到。
也可複製如下地址至瀏覽器直接前往獲取。
SmoONE 移動OA應用
https://github.com/comsmobiler/SmoONE
包含了GPS定位、IM等功能
SmoSEC 資產管理移動應用
https://github.com/comsmobiler/SmoSEC
資產管理移動應用,包含了條碼掃描、RFID掃描等功能
SmoWMS 倉庫管理移動應用
https://github.com/comsmobiler/SmoWMS
包含倉庫管理中的基本核心功能,固然倉庫管理中的條碼掃描、RFID掃描等也是不可少的
.NET移動開發,關於發佈IOS的方法(本人親身經歷折騰好久終於成功)
前情提要:這位.NET程序員兄弟使用Smobiler開發了一個APP,儘管Smobiler雲平臺已經最大限度的簡化了iOS應用的打包操做,但仍繞不開蘋果公司強制要求的p12文件,p12文件須要開發者自行生成,在此,qio763分享了這次生成p12文件的經驗,不管是初學iOS原生開發,仍是.NET移動開發平臺的smobiler,在生成iOS安裝包以前,p12文件生成這一步都是必經之路。
(P.S.提交了正確的p12文件後,應用已成功打包)
----------------------------------如下爲原文----------------------------------
在發佈IOS版本前,須要作的準備工做:
本人使用的虛擬主機,版本爲10.12(但不支持xcode10有點尷尬),若是你使用的MAC系統,能夠直接操做,虛擬主機方面請自行百度,此處不講
第一步,生成一個你的我的證書(鑰匙串)
第二步:進入IOS開發者中心進行相關的設置(此處很是重要,不少人包括我本人都出現了錯誤)
點擊Certificates下的all彈出的菜單中點擊+號,新添加一個你的我的證書,如已有證書可跳過此步
須要注意此步聚很重要,此處必須選擇紅框部分,由於smo發佈要求發佈正式版本,因此須要選擇此項,而後點擊continue直到出現如下畫面
點擊紅框部分,選擇剛纔咱們使用鑰匙串申請的文件
完成後點擊download下載到本地,雙擊剛下載的證書,將其導入到鑰匙串中
添加完成後,咱們須要將證書生成P12我的證書,這也是smo所須要的證書,咱們在鑰匙串中請行如下操做
右鍵點擊咱們剛纔添加的證書,選擇導出證書
導出證書時,文件格式默認爲P12,咱們就不要動了,也不要去管他,默認就好。
導出證書時需填寫一個你的導出密碼,這個密碼能夠隨意設置,但必須牢記,對應smobier中的導出密碼
到此,證書部分就算是完成了,企業證書原理同樣,操做方法也是這樣。下面是建立咱們的APPID與咱們的發佈描述。
發佈描述部分相對比較麻煩,不少用戶出錯基本都在這裏出錯(我本身在這出錯好幾回)
發佈描述,首先須要建立APPID
Identifiers》appids中點擊+號
須要注意的是BundleID必須與你的smobier的應用包名一致,若是不一致將沒法正常打包
必須勾選Push Notifications選項,包含了推送信息,而後點擊繼續按鈕直到完成
點擊剛建立的appid彈出詳細信息,咱們會發現,該功能並無應用,咱們點擊edit進行編輯
咱們會發現,關於Push Notifications部分有兩個選項,其實一個是測試版,一個是正式版,咱們這裏選擇正式版並建立,點擊繼續按鈕進入選擇頁面
點擊選擇按鈕,咱們選擇,咱們最開始用鑰匙串生成的文件,點擊繼續完成appid Push Notifications的修改,至此,appid建立完成,接下來就是發佈描述文件的生成了
Provisioning Profiles→Distribution
點擊Distribution中的+號
在此處咱們選擇正式版,也就是紅色框部分,點擊繼續
此處選擇,咱們剛纔建立的appid,此ID對應的是咱們的smobiler的包名
選擇咱們第一步建立的證書,點擊繼續,完成發佈描述,點擊download下載咱們的發佈描述文件
咱們在smobiler的應用平臺發佈IOS時,就將咱們剛纔生成的P12文件上傳,密碼填寫咱們導出P12證書的密碼,將下載的發佈描述文件上傳後,就能夠完成IOS的打包了
打包IOS很重要,特別是你的插件,若是包名錯誤了,再刪除是很難恢復的,個人插件就是由於打包操做出現問題就沒有了,很難過
做者:qio763
(原帖地址:https://www.smobiler.com/forum.php?mod=viewthread&tid=11605)