C#/.NET 基础学习


内容图片-底图-c#.net visual studio-开发框架文库

 

初识C#

 

C#是微软公司发布的面向对象的、运行于.NET Framework之上的高级程序设计语言。与Java有着明显不同,借鉴Delphi的特点,与COM(组件对象模型)直接集成,是微软公司 .NET windows网络框架的主角。
C#是一种语言,.net是一个平台。C#不但可以开发基于.net的应用程序,也可以开发基于WinForm的程序。. net 是 Microsoft 的 XML Web 服务平台,XML Web 服务能使应用程序在 Internet 上传输和共享数据。


 特点:  
  1. 强类型语言,安全稳定;
  2. 事件驱动、完全面向对象的可视化编程语言;
  3. 便捷的面向组件编程的支持;
  4. VB简单的可视化操作和C++的高运行效率的结合;
  5. 托管代码和垃圾回收 (garbage collection);


  // .NET ~ C# ~ ASP.NETC#是.net平台下的一种开发语言,用于开发桌面应用程序asp.net是开发web程序的技术 .net是平台,该平台下包含很多技术如:asp.net  ado.net  winform  WCF

 .NET框架
 CLR:公共语言运行库,Common Language Runtime,.NET框架的核心组件,在操作系统的顶层并在运行期调用基类库(BCL, Base Class Library)管理程序的执行。
  · 内存管理机制
  · 垃圾回收机制GC (Garbage Collector)
  · JIT编译器
 CTS:公共类型系统,Common Type System,重要特性是所有类型都继承自公共的基类object。


基础学习

 4个基础命名空间

// .NET框架中的基础类库,用于实现一些基本的类。
using System; .NET应用程序中使用的大多数基本类型
using System.Collections.Generic; 处理集合的泛型类型
using Syatem.Text; 字符串处理和编码相关的类型
using System.Linq; 提供支持使用语言集成查询(LINQ)进行查询的类和接口,用于对集合进行查询

 基础概念
0. 结构 - 类
 struct 是值类型,隐式密封的、不能被继承,但可以实现接口。struct 成员默认是 public,有构造函数(实例、静态),没有析构函数,不允许字段初始化。
 class 是引用类型,单继承,可实现接口。class 成员默认是 private。
  · 数据 成员:字段、常量;
  · 函数 成员:属性、方法、事件、索引器、构造函数、析构函数、操作符;
1. 字段 - 属性 - 索引
 字段 - private,属性 - public
 属性 是指定的一组2个匹配的、称为访问器 (get 和 set) 的方法。属性是函数成员,访问器只能被隐式调用,执行代码,但不为数据存储分配内存。公有属性提供对私有字段的受控访问。
 索引 是一组 get 和 set 访问器,类似属性,索引是函数成员;索引通常用于访问多个数据成员,类似数组利用索引运算符;索引不能声明为 static。访问器只能被隐式调用,可以重载,参数列表必须不同。
  · 索引没有名称,但 this 是必须的;
  · 参数列表中至少必须声明一个参数;

  ReturnType this[参数列表] {get {...}set {...}}

2. 静态构造函数 - (普通的)实例构造函数
 实例构造函数初始化类的每个新实例,static 构造函数初始化类层次的项目。static 构造函数不能访问类的实例成员,通常用于初始化类的静态字段,静态构造函数被系统自动调用。静态字段先于实例成员被初始化,类只能有一个 static 构造函数,不能带参数、不能有访问修饰符、也不能使用 this 访问器。
  [1]. 构造函数中不能调用虚方法;
  [2]. ;
  [3]. ;
3. 继承
 单继承。
 a. 重载:同一个类内的函数,函数名相同、参数列表不同;
 b. 重写(覆盖):父子类之间的函数,签名相同、返回类型相同;父类用 virtual 标识,子类用 override 标识;
 c. 隐藏:默认或通过 new 显式隐藏。base.数据成员/函数名 显式访问被隐藏的成员。
     · 字段:名称相同,类型相同; 
     · 函数:签名相同(函数名、参数列表(个数、顺序、类型、修饰符));
4. 抽象类 abstract - 接口 interface
 a. 抽象类可以给出某些成员的一些实现,接口不能包含成员实现;
 b. 抽象类的抽象成员可以被子类部分实现,接口的成员必须被实现类全部实现;
 c. 一个类只能继承一个抽象类(类单继承),但是可以实现多个接口;
 d. 类是对对象的抽象,抽象类是对类的抽象,接口是对行为的抽象
 e. 从设计角度,抽象类和接口设计的思维过程不同(相反):
   抽象类 - 自底向上,接口 - 自顶向下;
  - 接口 -
 引用类型,接口可以继承接口,类和结构可以实现接口。接口允许访问修饰符 public、protected、internal、private,接口成员不允许访问修饰符,默认 public static。接口声明不能包含数据成员,只能包含 属性、方法、事件、索引
 类 A 实现接口 IA,将类 A 的对象引用转换为接口 IA 的引用:
  a. 强制类型转换:IA ia = (IA)objA;但是若类 A 未实现接口 IA,则抛出异常。
  b. as 运算符:IA ia = objA as IA;若类 A 未实现接口 IA,返回 null、不抛出异常。
 实现接口的类可以从它的基类继承实现代码。类实现 2 个接口,2 个接口包含同名方法,类的单一实现就可以满足 2 个接口 或 显式实现每一个接口。同时可以分别获得每一个接口的独立引用。
  
  接口正常实现:接口方法不包含实现代码,实现在类级别的方法中;
  接口显式实现:接口方法包含实现代码,没有类级别的方法;
  :接口的显式实现成员只能被相应的接口引用访问,需要强制转换操作。
5. 密封类 - 抽象类 - 静态类
 a. 密封类:sealed,只能被用作独立的类,不能被继承,可实例化; 
 b. 抽象类:abstract,只能被继承,不可实例化;
 c. 静态类:static,静态类是密封的。不能被继承,不可实例化;
6. 装箱 - 拆箱
 a. 装箱:隐式转换,把值类型打包到Object引用类型的一个实例中;
 b. 拆箱:显式转换,从对象中提取值类型;
 implicit、explicit 和 is、as
 ·  implicit - 隐式转换,explicit - 显式转换;
    public static implicit/explicit operator 目标类型(源类型 源类型变量)
 :用户自定义转换仅针对于类和结构。is-as 不能用于用户自定义转换。is-as 不能重载。
 ·  is:检查对象类型兼容性并判断能否成功转换,返回bool,不抛出异常;
    适应范围:引用转换、装箱转换、拆箱转换,if(obj is Type) Type t = (Type)obj;
   as:类似强制转换,检查对象类型兼容性并返回转换结果,不抛出异常,失败时返回null;
    适应范围:引用转换、装箱转换,Type t = obj as Type; if(null !=t){…}
    true/成功:obj 是 Type 类型或者 obj 是 Type 类型的子类型;
   对于 is,CLR 对对象类型检查了次:is操作首先检查obj是否和Type类型兼容。若兼容,在if语句内执行转换时CLR再检查obj是否为一个Type引用并转换。对于 as,CLR 对对象类型检查了次:as操作检查兼容性并直接转换,效率高、性能好。
 参考:is - as 详解;
7. object sender - EventArgs e
 a. object sender:保存触发事件的对象的引用,指向发送通知的对象;
 b. EventArgs e:EventArgs 是包含事件数据的类的基类,在事件触发时传递数据,但是 EventArgs 不包含任何数据,所有的事件参数类都必须从 EventArgs 类派生;
8. 变体
 变体分为 协变 - 抗变 两种,针对引用类型:
 a. 协变:covariance,父=子,out,只能用作方法的返回值或属性get的访问器;
 b. 抗变:contravariance,子=父,in,只能用作方法的参数;
9. 可空类型 ? - 空接合运算符 ??
 a. 可空类型允许创建普通值类型的变量并标注其有效性。可空类型是对普通值类型的 private 封装,其问号语法是通过 System.Nullable<T> 利用泛型实现,与普通值类型可以相互转换。不能创建引用类型的可空类型。2 个只读属性:
  - HasValue:bool 类型,标识是否有效; 
  - Value:变量值;(普通值类型的值、可空类型的值、null
 b. 空接合运算符允许在可空类型的变量为 null 时返回一个给定值。 
10. 泛型
 类型是实例对象的模板,泛型类型是类型的模板。
 类型参数的约束用 where 子句列出:where 参数:constraint, constraint, …
  · 构造函数约束 new() 必须放在最后;
  · 主约束(class/struct)至多一个,且必须放在第一位; 
  · 接口约束可以有多个;
 只有 Type 类型或派生于 Type 类型的实参才能用于受约束的参数。 
 
委托 - 事件
 a. 委托 delegate:对函数的封装,一种引用方法的类型 (引用类型),代表一类方法,具有相同参数列表和返回类型;
 b. 事件 event:委托的一种特殊情形,事件的类型是委托,事件是委托类型的变量,事件不是类型,事件是成员(变量)且被隐式自动初始化为null;
  利用”+=”增加委托的实例/静态方法,利用”-=”移除委托的实例/静态方法。事件被触发时,执行被委托的方法(调用委托来依次调用调用列表中的方法)。此处引用大话设计模式中的例子:
  public delegate void CatShoutEventHandler(object sender, EventArgs e);
  public event CatShoutEventHandler CatShout;
  委托是面向对象、类型安全的并且是可靠受控、安全的。当委托被调用时,它调用有序方法列表中的每一个方法。委托是恒定的,委托对象被创建后就不会再被改变。调用空委托会抛出异常,通过把委托和null比较判断委托的调用列表是否为空,进而判断委托是否为null。
 泛型委托
  public delegate TR FunHandler<T1T2TR>(T1 p1, T2 p2)
 匿名方法 -> Lambda表达式
  匿名方法,anonymous method,可以避免创建使用独立的具名方法,允许在创建并初始化委托或为委托增加方法时包含小段的内联inline代码。
    delegate(参数列表){语句块};
  Lambda表达式避免冗余信息、简化匿名方法的语法。
 总结: 从 委托事件 到 观察者模式;
 
扩展方法
 允许向现有类型"添加"方法,而无需创建新的派生类型、重新编译或以其他方式修改原始类型。类A需要新增一个方法,但类A是密封的或源代码不可见,即不能修改类A,此时扩展方法允许在另一个类B中利用类A的公有可用成员实现类A需要新增的方法。
  · 扩展方法必须是静态的,所在类也必须是静态的;
  · 被扩展类型必须作为第一个参数,必须用 this 修饰; 
 public static class ExtendMyClass {
   public static 返回类型 Function(this MyClass mc) {
      // 调用MyClass的公共成员实现新增方法
   }
 }
 调用:mc.Function();,如果没有this,只能以ExtendMyClass.Function(mc);方式调用。
 扩展方法还可以结合泛型类,允许将(扩展)类中的静态方法关联到不同的泛型类上。扩展接口时,利用扩展方法比继承接口(会强制要求实现接口下的所有方法)更方便。但是,扩展方法的优先级总是比被扩展类型本身中定义的同名实例方法低,且被扩展类型的子类不能继承其父类型的扩展方法。
  · 将静态方法转成扩展方法,扩展方法本质上是静态方法;
  · 编写帮助类;
  · 为 Linq 服务,实现链式编程;
 参考:谈扩展方法的理解; C#扩展方法;
    奇思妙想之扩展方法系列;
 
枚举 ~ 枚举数 ~ 可枚举类型
 枚举 enum,值类型,成员是整数值常量,可以显式为其赋值初始化,但不能使用修饰符。枚举可用于实现位标志,注意添加 [Flags] 特性。
 可枚举类型是实现了GetEnumerator()方法的类型,返回用于(读取并返回)集合中数据项的枚举数,枚举数是可以依次返回集合中数据项的类对象。
 参考:迭代器学习系列;自定义类实现foreach;
 [-1-]. IEnumerable / IEnumerator
  非泛型枚举数和可枚举类型,枚举数类通常声明为类中的嵌套类。
  ·   IEnumerator
   - Current:当前位置对应的数据项;
   - MoveNext():下移位置,初始位置为-1;
   - Reset():复位;
  ·   IEnumerable
   - IEnumerator GetEnumerator(): 
 [-2-]. IEnumerable<T> / IEnumerator<T>
  泛型枚举数和可枚举类型,类型安全。
 总结:IEnumerable / IEnumerator 学习 - sqh  
   
 某些重要的关键字/修饰符/运算符
0. object 类
 C#中所有的类(型)都直接/间接继承自System.Object类(型),值类型数据可以隐式转换为Object类型;object是引用类型,关键字object就是System.Object的别称。
   静态方法 
 [1]. public static bool Equals(object objA, object objB){}
   调用实例方法Equals(object obj),判断是否相等;
 [2]. public static bool ReferenceEquals(object objA, object objB){}
   判断两个对象是否引用相等;
   实例方法
 [1]. public virtual bool Equals(object obj){}
   方法需要重写用于实现根据值来判断对象是否相等;
 [2]. public virtual int GetHashCode(){}:获取对象的Hash值;
 [3]. public Type GetType(){}
   获取当前实例的Type,查询对象的元数据来确定对象的运行时类型;
 [4]. public virtual string ToString(){}:获取当前实例的字符串信息,对象的字符串表达形式;
   受保护方法
 [1]. protected virtual void Finalize(){}
   类或派生类可以访问,允许 Object 在“垃圾回收”机制回收 Object 之前尝试释放资源并执行其他清理操作;
 [2]. protected object MemberwiseClone(){}:创建当前实例的浅表副本;
1. partial
 a. 把类定义放在多个代码文件中;
 b. 用于创建部分方法(定义声明和方法实现),不能有访问修饰符,返回值必须为 void;
2. internal
 类和类成员的访问修饰符,同一程序集权限。类默认是 internal,类成员默认是 private。
 protected internal:受保护的内部成员,同一程序集 or 子类权限。
 参考:internal - 举例参考
 嵌套类:嵌套是指类声明的位置,而不是类实例的位置。
 嵌套类具有成员访问级别,默认 private,可见性具体地:
  ·  嵌套类型的成员对封闭类型的成员具有完全访问权限;
  ·  封闭类型的成员只能访问嵌套类型的public和internal成员,不能访问private和protected成员;
 嵌套类型的对象访问封闭类型,需要维护封闭类型的引用。
3. using
 a. using 指令:命名空间指示符
 b. using 别名:类型别名指示符
  一个.cs文件引用了两个不同的命名空间,但两个空间都包括一个相同名字的类型,使用别名更简洁。
  using aClass = NameSpaceA.MyClass;
  using bClass = NameSpaceB.MyClass;
 c. using语句:资源的包装和管理 -> 隐式的 try…finally 块
  定义一个范围,在范围结束时自动处理对象,自动调用这个类实例的 Dispose 方法。资源是一个实现 System.IDisposable 接口的类或结构。
4. 异常try…catch…finally
 结构化异常处理语法,标记出能处理异常的代码和指令:
  ■  try:包含可能会抛出异常的代码;
  ■  catch:抛出异常后要执行的代码,catch块可多个;
  ■  finally:始终一定会执行的代码,释放资源;
 try 块是必须的,catch 和 finally 必须至少有一个。所有的异常类均派生于 System.Exception 类。
 异常嵌套的处理:如果异常出现在 Method2 方法内部,但是其 catch 块没有匹配的异常处理程序, 系统沿着调用栈向上搜索到 Method1,如果找到匹配的 catch 块,系统先回到栈顶 Method2 处执行其 finally 块,然后把 Method2 从调用栈中 pop(),最后执行 Method1 的相应 catch 块和 finally 块。

 public void Method2()                    public void Method1()     {                                         {try{                                      try{...                                       Method2();}                                         }catch{...}                                catch{...}finally{...}                               finally{...}}                                         }

  ■  throw:显式抛出异常;
   -  throw Exception;异常抛出后,异常实例可以被 catch 块捕获。
   -  throw;此种只能在 catch 块内,捕获后再重新抛出。
5. String、StringBuffer 与 StringBuilder
 String是字符串常量、定长,StringBuffer与StringBuilder是字符串变量、可变长、避免产生额外的临时变量;StringBuffer线程安全,StringBuilder是非线程安全,三者的执行速度 StringBuilder > StringBuffer > String。具体区别详见:
 参考: String - StringBuffer - StringBuilder.
 string - String
 String是.NET Framework中的类,string是C#中的类,C#的string映射为.NET Framework的String;string是C#中的关键字,可以作为String或System.String的别名;
6. const 与 readonly
 const只能在声明语句中初始化,readonly可以在声明语句或构造函数中初始化,const是编译时常量、在内存中没有存储位置,readonly是运行时常量、在内存中有存储位置;const是静态的,readonly可以是静态字段也可以是实例字段。
7. typeof 与 GetType
 typeof:一元运算符,返回作为它的参数的任何类型的 System.Type 对象,不能重载。
 GetType:方法,可以调用 typeof 运算符,对任意类型的任意对象都有效。
8. var
 推断类型,弱化类型的定义,可替代任何类型,但是 var 并不改变 C# 强类型性质。类似object,但object是引用类型,效率比var低。
 var 用于本地局部变量,不能用于字段,使用时必须初始化且不能再次赋类型不同的值;
 

 常用函数
1. Convert.ToInt32 - int.Parse(Int32.Parse)- int.TryParse - (int)
 a. Convert.ToInt32与int.Parse类似,Convert.ToInt32 内部调用了int.Parse,Convert.ToInt32 可以转换的类型较多,int.Parse只能转换数字类型的字符串;


 b. int.TryParse与int.Parse类似,但不会抛出异常,返回值为bool以指示解析是否成功,从而可以免去添加异常处理代码的麻烦,out参数为转换输出值;
 此四者都可以解释为将类型转换为 int,eg:举例参考.
 :所有预定义的简单类型均包含静态方法 Parse,将字符串解析为相应的数据值。
2. Split
 String类的内置方法,分割函数,参数可以为单个字符、多个字符、字符串。
 参考:Split - 常用举例参考,Split的不同重载方法.
3. Trim
 String类的内置方法,用于去除字符串前后的指定字符,另外还有TrimStart()和TrimEnd()方法。
 参考:Trim - 举例参考.
4. DateTime
 · 与字符串string的转换
  - DateTime.Parse(timeString);
  - Convert.ToDateTime(timeString);
  - if (DateTime.TryParse(timeString, out datetime)) {
     DateTime dm = datetime;
   }
 · DateTime
 
x. xxx

 


集合类数据存储和检索

命名空间:using System.Collections;
     using System.Collections.Generic;
 ArrayList 对应的泛型集合是 List,与 HashTable 对应的泛型集合是 Dictionary
 - ArrayList:是Array的复杂版本,动态数组,实现了ICollection和IList接口,针对任意类型、任意长度,非类安全型的;
  声明:ArrayList mAList = new ArrayList();
  具体地属性方法类似List,此处不再赘述。 
 - HashTable:每个元素都是一个存储在DictionaryEntry对象中的键值对。keyvalue键值对均为object类型,支持任何类型的keyvalue键值对,非类安全型的;线程安全的;
  声明:Hashtable ht = new Hashtable();
  遍历哈希表元素:
   foreach(DictionaryEntry de in ht)
  哈希表排序:
   ArrayList KeysAList = new ArrayList(ht.Keys);
   KeyAList.Sort();
1. 泛型List
 声明:List<T> mList = new List<T>();
 属性方法:
  - mList.Count:对链表mList元素计数
  - mList.Add(T item):添加元素
  - mList.Insert(int pos, T item):指定位置插入元素
  - mList.AddRange(List list):链接2个List
  - mList.Contains(T item):测试List是否包含元素item
  - mList.Item(int idx):索引器,通过指定索引获取或设置元素
  - mList.Remove(T item):删除指定的元素
  - mList.RemoveAt(int pos):删除指定位置的元素(推荐)
  - mList.RemoveRange(int b, int n):删除从b开始的n个元素
  - mList.Clear():清空List
  - mList.Reverse():反转List
  - mList.Sort():排序List
2. 泛型Dictionary
  在C#中,Dictionary提供快速的基于键值的元素查找。Dictionary<[key], [value]>,键必须唯一且不能为空引用null,值若为引用类型则可以为空。
 声明:Dictionary<T1, T2> mDict = new Dictionary<T1, T2>();
 属性方法:
  - mDict.Count:对字典mDict元素计数
  - mDict.Add(T1 key, T2 value):添加元素(键, 值)对
  - mDict.ContainsKey(T1 key):字典是否包含键为key的元素
  - mDict.ContainsValue(T2 value):字典是否包含值为value的元素
  - mDict.Remove(T1 key):移除键为key的元素
  - mDict.Clear():清空Dict
  - 遍历字典元素
    1. By KeyValuePair
     foreach (KeyValuePair<T1, T2> kvp in mDict) 或 foreach(var kvp in mDict)
    2. By Key
     Dictionary<T1, T2>.KeyCollection keyCol = mDict.Keys;
     foreach (T1 key in keyCol)  或  foreach(T1 key in mDict.Keys) 
    3. By Value
     Dictionary<T1, T2>.ValueCollection valueCol = mDict.Values;
     foreach (T2 value in valueCol)  或  foreach(T2 value in mDict.Values)
  - mDict[key] = value:通过索引器读写键值对
  - mDict.TryGetValue(T1 key, out value_T2):获取与指定的键相关联的值。通过键取值,包括两个参数,一个是要查询的键,另一个是获取的值,注意值前面使用out关键字。
  注:“判断键存在”和“根据键取值”两步转化为一步,键的哈希值只计算一次,效率高。
 以下三个集合类,可以进一步参考 Stack - Queue - SortedList.
3. SortedList
 System.Collections.SortedList类表示按键排序的键/值对的集合,可以按键或索引访问,是数组和哈希表的组合。
 声明:SortedList sList = new SortedList();
 遍历排序列表元素:
  foreach(DictionaryEntry de in sList)
 - 泛型SortedList
 
4. 堆栈 Stack
 System.Collections.Stack类表示对象的LIFO集合,处理顺序多变。
 声明:Stack st = new Stack();
 属性方法:
  - st.Peek:取栈顶元素,但不将其移除;
  - st.Push(object obj):栈顶入栈;
  - st.Pop():出栈,移除并返回位于Stack栈顶处的对象;
 - 泛型Stack

5. 队列 Queue
 System.Collections.Queue类表示对象的FIFO集合,顺序处理集合中的对象。
 声明:Queue qu = new Queue();
 属性方法:
  - qu.Peek:取队首元素,但不将其移除;
  - qu.Enqueue(object obj):队尾入队;
  - qu.Dequeue():出队,移除并返回位于Queue开始处的对象;
 - 泛型Queue
 
 当有多个线程并发访问集合时,应该用System.Collections.Concurrent命名空间代替上述命名空间中的对应类型,线程安全的集合类可由多个线程同时访问:
 - ConcurrentDictionary
 
 - ConcurrentQueue

版权声明:本文为开发框架文库发布内容,转载请附上原文出处连接
C/S框架网
上一篇:C# .NET 入门概念与知识点总结
下一篇:No Entity Framework provider found for the ADO.NET provider with invariant name 'System.Data.SqlClient'
评论列表

发表评论

评论内容
昵称:
关联文章

C#/.NET 基础学习
学习C#.NET基础知识(学习重点请下载附件)
C#.NET学习路线导引
学习版(精简版)与基础版区别
学习C#.NET推荐几本书籍
C#.Net培训大纲(学习重点)
C#语言学习思维导图,c#思维导图
C#.NET LINQ入门基础
C#.NET Log4Net日志的基础用法
学习C/S结构开发框架从MDI起步
C#基础教程(上)(菜鸟教程笔记),c# 教程
VSCode+VUE+Element-UI学习资料大全
学习版(精简版)与正式版(标准版、高级版)区别
不错的框架,这套开发框架好学习吗?
C# 对象多态性(OOP基础)
C#基础之索引器(Indexer)
C# LINQ基础-Linq基本使用方法
CSFramework开发框架ADO.NET学习要点
C/S Winform开发框架 - 单表基础资料窗体实现主从表资料管理
Vue学习笔记-2022

热门标签
.NET5 .NET6 .NET7 APP Auth-软件授权注册系统 Axios B/S B/S开发框架 Bug Bug记录 C#加密解密 C#源码 C/S CHATGPT CMS系统 CodeGenerator CSFramework.DB CSFramework.EF CSFrameworkV1学习版 CSFrameworkV2标准版 CSFrameworkV3高级版 CSFrameworkV4企业版 CSFrameworkV5旗舰版 CSFrameworkV6.0 DAL数据访问层 Database datalock DbFramework Demo教学 Demo下载 DevExpress教程 DOM EF框架 Element-UI EntityFramework ERP ES6 Excel FastReport GIT HR IDatabase IIS JavaScript LINQ MES MiniFramework MIS NavBarControl Node.JS NPM OMS ORM PaaS POS Promise API Redis SAP SEO SQL SQLConnector TMS系统 Token令牌 VS2022 VSCode VUE WCF WebApi WebApi NETCore WebApi框架 WEB开发框架 Windows服务 Winform 开发框架 Winform 开发平台 WinFramework Workflow工作流 Workflow流程引擎 版本区别 报表 踩坑日记 操作手册 代码生成器 迭代开发记录 基础资料窗体 架构设计 角色权限 开发sce 开发技巧 开发教程 开发框架 开发平台 开发指南 客户案例 快速搭站系统 快速开发平台 秘钥 密钥 权限设计 软件报价 软件测试报告 软件简介 软件开发框架 软件开发平台 软件开发文档 软件体系架构 软件下载 软著证书 三层架构 设计模式 生成代码 实用小技巧 收钱音箱 数据锁 数据同步 微信小程序 未解决问题 文档下载 喜鹊ERP 喜鹊软件 系统对接 详细设计说明书 行政区域数据库 需求分析 疑难杂症 蝇量级框架 蝇量框架 用户管理 用户开发手册 用户控件 在线支付 纸箱ERP 智能语音收款机 自定义窗体 自定义组件 自动升级程序