c#语言_c#语言规范 - CSDN
c#语言 订阅
C语言是一门面向过程的、抽象化的通用程序设计语言,广泛应用于底层开发。C语言能以简易的方式编译、处理低级存储器。C语言是仅产生少量的机器语言以及不需要任何运行环境支持便能运行的高效率程序设计语言。尽管C语言提供了许多低级处理的功能,但仍然保持着跨平台的特性,以一个标准规格写出的C语言程序可在包括类似嵌入式处理器以及超级计算机等作业平台的许多计算机平台上进行编译。 [1] 展开全文
C语言是一门面向过程的、抽象化的通用程序设计语言,广泛应用于底层开发。C语言能以简易的方式编译、处理低级存储器。C语言是仅产生少量的机器语言以及不需要任何运行环境支持便能运行的高效率程序设计语言。尽管C语言提供了许多低级处理的功能,但仍然保持着跨平台的特性,以一个标准规格写出的C语言程序可在包括类似嵌入式处理器以及超级计算机等作业平台的许多计算机平台上进行编译。 [1]
信息
类    别
程序设计语言
影响语言
C++、C#、D、Java、JavaScript、ObjectPHP等
创始时间
1972年
主要编译器
Visual C++、Clang、GCC、Turbo C等
中文名
C语言
创始人
Dennis MacAlistair Ritchie
发    源
BCPL语言
外文名
C Programming Language
c语言简介
C语言是一门面向过程的计算机编程语言,与C++、Java等面向对象编程语言有所不同。C语言的设计目标是提供一种能以简易的方式编译、处理低级存储器、仅产生少量的机器码以及不需要任何运行环境支持便能运行的编程语言。C语言描述问题比汇编语言迅速、工作量小、可读性好、易于调试、修改和移植,而代码质量与汇编语言相当。C语言一般只比汇编语言代码生成的目标程序效率低10%~20%。因此,C语言可以编写系统软件。 [2]  当前阶段,在编程领域中,C语言的运用非常之多,它兼顾了高级语言和汇编语言的优点,相较于其它编程语言具有较大优势。计算机系统设计以及应用程序编写是C语言应用的两大领域。同时,C语言的普适较强,在许多计算机操作系统中都能够得到适用,且效率显著。 [3]  冯.诺依曼在1945年提出了现代计算机的若干思想,被后人称为冯.诺依曼思想,这是计算机发展史上的里程碑。自1945 年至今大多采用其结构,因此冯.诺依曼被称为计算机之父。他的体系结构计算机由运算器、控制器、存储器、输入设备、输出设备五大部件构成。 C语言拥有一套完整的理论体系经过了漫长的发展历史,在编程语言中具有举足轻重的地位。 [4] 
收起全文
精华内容
参与话题
  • 零基础学C#编程—C#从小白到大咖

    万人学习 2019-06-04 13:18:37
    本课程从初学者角度出发,提供了C#从入门到成为程序开发高手所需要掌握的各方面知识和技术。 【课程特点】 1 由浅入深,编排合理; 2 视频讲解,精彩详尽; 3 丰富实例,轻松易学; 4 每章总结配有难点解析...
  • 初级学软件之C#语言

    千人学习 2016-12-17 17:46:55
    主讲内容: 第一讲 Hello World 实例(完结) 第二讲 面向对象的实例(完结) 第三讲 变量(完结) 第四讲 常量(完结) 第五讲 数据类型(完结) 第六讲 运算符(完结) 第七讲 判断语句(完结) ...等19讲
  • 【编程语言C# 从菜鸟到高手

    千次阅读 2018-06-14 20:35:41
    1 Overview 1.1 CLI common language infrastructure ...The .NET Framework, .NET Core, Mono, ...能更容易的设计跨语言交互的组件和应用程序,也就是不同语言的对象能相互通信 CLR 某种意义上可理解为 Jav...

    1 Overview

    1.1 CLI

    • common language infrastructure
    • The .NET Framework, .NET Core, Mono, DotGNU and Portable.NET are implementations of the CLI.
    • 能更容易的设计跨语言交互的组件和应用程序,也就是不同语言的对象能相互通信
    • CLR 某种意义上可理解为 Java 的 JVM,而 MSIL 相当于 Java 中的字节码;

    1.2 .NET Framework 是什么

    .NET Framework 由一个巨大的代码库组成,适用于 C#,C++,VB,Jscript,COBOL等等,这些语言可以访问框架,彼此之间也可以相互访问:

    1.3 C# 语言特征

    C# is a multi-paradigm programming language encompassing strong typing, imperative, declarative, functional, generic, object-oriented (class-based), and component-oriented programming disciplines.

    • 布尔条件(Boolean Conditions)
    • 自动垃圾回收(Automatic Garbage Collection)
    • 标准库(Standard Library)
    • 组件版本(Assembly Versioning)
    • 属性(Properties)和事件(Events)
    • 委托(Delegates)和事件管理(Events Management)
    • 易于使用的泛型(Generics)
    • 索引器(Indexers)
    • 条件编译(Conditional Compilation)
    • 简单的多线程(Multithreading)
    • LINQ 和 Lambda 表达式
    • 集成 Windows

    1.4 Programming paradigms

    编程范式

    1. imperative programming
    2. declarative programming
    3. structured programming, block-structured programming
    4. modular programming
    5. object-oriented programming
    6. 命令式编程语言与声明式编程语言,前者更关注于怎么做,how,后者更关注于做什么,what;
    7. Procedural programming is a type of imperative programming; 程序由若干过程(subroutine,function,)组成;
    8. proc, def, sub, func, …
    9. From the 1960s onwords, structured programming and modular programming in general have been promoted as a techniques to improve the maintainability and overall quality of imperative programs. And then is object-oriented programming.
    10. The hardware implementation of almose all computers is imperative.

    <待续>

    2 C# 基础

    2.1 关键字

    1. namespace, using : Java 中通过 package,import 来管理命名空间, 可嵌套,如 System.Console
    2. 标识符可以以 @ 开头,比如@if,第一个字符不能是数字

    保留关键字:

    • checked/unchecked
    • decimal : 128 bit 十进制值
    • default
    • delegate
    • event
    • explicit/implicit
    • extern
    • fixed
    • foreach : 遍历数组 foreach (int j in intArray)
    • in
    • internal
    • is : 判断对象是否为某类型, if(xiaoming is JingCha)
    • as : 强制类型转换, StringReader r = obj as StringReader;
    • lock
    • namespace
    • object
    • operator : 运算符重载
    • out
    • params : 不定参数
    • readonly
    • ref
    • sealed : 密封类不能被继承,Java 中为 final
    • sizeof :获取一个类型或变量的存储大小,sizeof(stype) == 2
    • stackalloc : 在栈上分配空间,用于 unsafe code
    • struct
    • typeof: 获取 class 的类型,typeof(StreamReader)
    • unsafe
    • virtual : virtual 方法可以在不同的继承类中有不同的实现,C# 通过抽象类和虚方法来实现动态多态性
    • volatile
    • & : 返回变量的地址

    上下文关键字:

    • add
    • alias
    • ascending/descending
    • dynamic : 运行时进行类型检查,而不是编译期
    • from
    • get
    • global
    • group
    • into
    • join
    • let
    • orderby
    • partial
    • remove
    • select
    • set

    2.2 类型

    2.2.1 引用

      引用是一个指向实际存储空间的一个指针,C#的引用类型有: object,dynamic,string

      object 可以理解为 void *,在使用时,需要进行类型转换。当一个值类型转换为对象类型时,称为装箱;当一个对象类型转换为值类型时,称为拆箱。

    object obj;
    obj = 100
    

      在 java 中:

    Integer num = 100;
    Object obj = 100;
    

      dynamic 变量的类型检查时在运行时发生的, 而对象类型变量的类型检查时在编译时发生的。

    dynamic a = 20;
    

      String 类型允许给变量分配任何字符串值,可以通过两种形式:引号和@引号

    string a = @"c:\windows";
    string b = "c:\\windows";
    string c = @"<script type=""text/javascript"">
        <!--
        -->
    </script>"; // 在写usage方法时,非常有用
    

    2.2.2 指针类型

    C# 中指针与 c/c++中的指针有相同的功能。

    type* tptr;
    char* cptr;
    int* iptr;
    

    2.2.3 变量

    本质上讲,变量就是特定内存的名称,而类型就是变量所指的内存块的大小。

    int num = Convert.ToInt32(Console.ReadLine());
    

    2.3 封装

    访问修饰符:

    1. public
    2. private
    3. protected
    4. internal : 只有同一个程序集的对象可以访问
    5. protected internal

    2.4 参数传递

    • 值参数 : 赋值参数的实际值,实参和形参使用不同的内存区,方法调用不影响实参的值;
    • 引用参数 : 会改变实参的值
    • out 参数 : 接收返回结果,使用out就不需要通过赋值获取 return 的值了。
    void swap_ref(ref int x, ref int y){ int tmp = x; x = y; y = tmp;};
    void swap_value(int x, int y) {int tmp = x; x = y; y = tmp;};
    void value_out(out int x) {x=8;};
    

      对应 java 代码:需要特别注意的是,引用本身是值变量,在进行参数传递的时候,实参和形参是不同的引用!

    public static void getValue(Integer a) {
        a = 200; /、 这里的 a 引用跟形参传入的 b 已经是不同的变量了
    }
    
    public static void getValue(int[] a) {
        a[1] = 5;
    }
    
    
    Integer b = new Integer(100);
    getValue(b);
    System.out.println(b); // b = 100
    
    int[] c = {1, 2, 3};
    getValue(c);
    System.out.println(c[1]); // c = {1, 5, 3}
    

      感受一下 Java 与 C# 之间的不同!

    2.5 Nullable

    int i; // 默认值为 0
    int? j; // 默认值为 null
    

      首先,primitive type 如 int,double,bool 等无法直接赋值null,比如在 java 中:

    int i; // compile error: 变量 i 未初始化
    int i = null; // compile error: 不兼容的类型,nulltype 无法转换为 int;
    Integer i = null; // OK
    

      在处理数据库和其他包含可能为负值的元素的数据类型时,将 null 赋值给数值类型或布尔型的功能特别有用。

      比如使用 Hibernate 时,如果数据表中的 column 时允许为 null 的,那么 Entity 中的类型必须为 Integer,而不能为 int,否则就会出错。

    2.6 String

    • String.Join
    • String.Format
    • String.Compare
    • String.Concat
    • String.Contains
    • String.Copy
    • String.Equals
    • String.EndsWith
    • String.IndexOf
    • String.Insert
    • String.Remove
    • String.Replace
    • String.Split
    • Strint.Trim
    • String.ToLower
    • String.TOUpper
    • String.Length
    //方法返回字符串
    string[] sarray = { "Hello", "From", "Tutorials", "Point" };
    string message = String.Join(" ", sarray);
    Console.WriteLine("Message: {0}", message);
    
    //用于转化值的格式化方法
    DateTime waiting = new DateTime(2012, 10, 10, 17, 58, 1);
    string chat = String.Format("Message sent at {0:t} on {0:D}", 
    waiting);
    Console.WriteLine("Message: {0}", chat);
    

    2.7 Struct 结构体

    结构体是值类型,不是引用类型,是用来代表一个记录。

    struct Books 
    {
        public string title;
        public string author;
        public string subject;
        public int id;
    }
    
    Books book; // 已经进行了实例化,即分配了book的存储区
    
    • 可以带有方法、字段、索引、属性、运算符方法和事件;
    • 可定义构造函数,不能定义析构函数
    • 不能被继承
    • 可以实现多个接口
    • 成员访问描述符不能为: abstract,virtual,protected
    • 与类不同,接口实例化可以不适用 New

      引用对象的值是存储在堆空间的,值类型的对象值是存储在栈上的, 生存期不同。内存访问方式不同,效率也不一样,但是栈空间大小是有限的。

    2.8 Enum 枚举

      C# 枚举是值类型,不能被继承;

    enum Days { Sun, Mon, Tue, Wed, Thu, Fri, Sat};
    

    2.9 Class

    成员函数: 对象的方法
    成员变量: 对象的属性

    2.9.1 继承的形式

    <acess-specifier> class <base_class>
    {
     ...
    }
    
    <acess-specifier> interface <base_interface>
    {
     ...
    }
    
    class <derived_class> : <base_class>, <base_interface>
    {
     ...
    }
    
    
    • Java 中需要关键字 extends, implements 来实现继承;
    • C# 不支持多重继承,单可以使用接口来实现多重继承
    • 通过 inteface 来定义接口

    2.9.2 多态

      简单的说,就是相同的接口,不同的行为;在编程语言层面,又分为静态多态性与动态多态性,也称为静态绑定与动态绑定。静态绑定主要是指函数重载,运算符重载;而动态绑定则指函数重写(),C# 通过抽象类和虚方法来实现动态多态性。

      C# 中的 virtual, override 在 Java 中体现为 @Override 方法。

    2.10 运算符重载

    public static result-type operator unary-operator ( op-type operand )
    public static result-type operator binary-operator ( op-type operand, op-type2 operand2 )
    public static implicit operator conv-type-out ( conv-type-in operand )
    public static explicit operator conv-type-out ( conv-type-in operand )
    
    • result-type 运算符的结果类型。
    • unary-operator 下列运算符之一:+ - ! ~ ++ — true false
    • op-type 第一个(或唯一一个)参数的类型。
    • operand 第一个(或唯一一个)参数的名称。
    • binary-operator 其中一个:+ - * / % & | ^ << >> == != > < >= <=
    • op-type2 第二个参数的类型。
    • operand2 第二个参数的名称。
    • conv-type-out 类型转换运算符的目标类型。
    • conv-type-in 类型转换运算符的输入类型。

    2.11 预处理指令

      预处理器指令指导编译器在实际编译开始之前对信息进行预处理。

    • define 它用于定义一系列成为符号的字符。
    • undef 它用于取消定义符号。
    • if 它用于测试符号是否为真。
    • else 它用于创建复合条件指令,与 #if 一起使用。
    • elif 它用于创建复合条件指令。
    • endif 指定一个条件指令的结束。
    • line 它可以让您修改编译器的行数以及(可选地)输出错误和警告的文件名。
    • error 它允许从代码的指定位置生成一个错误。
    • warning 它允许从代码的指定位置生成一级警告。
    • region 它可以让您在使用 Visual Studio Code Editor 的大纲特性时,指定一个可展开或折叠的代码块。
    • endregion 它标识着 #region 块的结束。

    2.12 正则表达式

    Regex

    • Regex.IsMatch
    • Regex.Matches
    • Regex.Replace
    • Regex.Split

    2.13 异常处理

    • System.IO.IOException 处理 I/O 错误。
    • System.IndexOutOfRangeException 处理当方法指向超出范围的数组索引时生成的错误。
    • System.ArrayTypeMismatchException 处理当数组类型不匹配时生成的错误。
    • System.NullReferenceException 处理当依从一个空对象时生成的错误。
    • System.DivideByZeroException 处理当除以零时生成的错误。
    • System.InvalidCastException 处理在类型转换期间生成的错误。
    • System.OutOfMemoryException 处理空闲内存不足生成的错误。
    • System.StackOverflowException 处理栈溢出生成的错误。

    2.14 文件 IO

    • BinaryReader 从二进制流读取原始数据。
    • BinaryWriter 以二进制格式写入原始数据。
    • BufferedStream 字节流的临时存储。
    • Directory 有助于操作目录结构。
    • DirectoryInfo 用于对目录执行操作。
    • DriveInfo 提供驱动器的信息。
    • File 有助于处理文件。
    • FileInfo 用于对文件执行操作。
    • FileStream 用于文件中任何位置的读写。
    • MemoryStream 用于随机访问存储在内存中的数据流。
    • Path 对路径信息执行操作。
    • StreamReader 用于从字节流中读取字符。
    • StreamWriter 用于向一个流中写入字符。
    • StringReader 用于读取字符串缓冲区。
    • StringWriter 用于写入字符串缓冲区。

    3 高级特性

    3.1 Attribute

      C# 的 Attribute 类似于 Java 的 Annotation,用于在运行时向程序传递在代码元素(如类、方法、结构、枚举、组件等)中声明的各类信息。

      Attribute 用于添加元数据,如编译器指令和注释、描述、方法、类等其他信息,有预定义特性和自定义特性两类。

      语法:

    [attribute(positional_parameters, name_parameter = value, ...)]
    element
    

    3.1.1 预定义特性

    1. AttributeUsage
    2. Conditional
    3. Obsolete : 在 java 中使用 @Deprecated

    3.1.2 创建自定义特性

    。。。

    3.2 反射 Reflection

      反射是指程序可以访问、检测和修改它本身状态和行为的一种能力。

      程序集包含模块,模块中有类,类有成员和方法,反射则封装了描述程序、模块、类等元信息的对象。可以通过反射动态地创建类型的实例,或者将类型绑定到现有对象,或者从现有对象中获取类型,还可以在运行时获取特性的信息。

      优点:

    • 反射提高了程序的灵活性和扩展性。
    • 降低耦合性,提高自适应能力。
    • 它允许程序创建和控制任何类的对象,无需提前硬编码目标类。

      缺点:

    • 性能问题:使用反射基本上是一种解释操作,用于字段和方法接入时要远慢于直接代码。因此反射机制主要应用在对灵活性和拓展性要求很高的系统框架上,普通程序不建议使用。
    • 使用反射会模糊程序内部逻辑;程序员希望在源代码中看到程序的逻辑,反射却绕过了源代码的技术,因而会带来维护的问题,反射代码比相应的直接代码更复杂。

      MemberInfo 对象中封装了类型信息

    System.Reflection.MemberInfo info = typeof(MyClass);

    3.3 属性 Property

      属性是 field 的扩展,通过访问器来访问。

      访问器通过上下文关键字 get/set 来定义。

        class Student
       {
    
          private string code = "N.A";
    
          // 声明类型为 string 的 Code 属性
          public string Code
          {
             get
             {
                return code;
             }
             set
             {
                code = value;
             }
          }
        }
    

    3.4 索引器

      允许一个对象可以像被数组一样被索引,当为一个类定义一个索引器时,该类的行为就会想一个虚拟数组一样,可以使用[]来访问。

      有点类似于运算符重载的一个特例,[] 本质上可以看作为运算符,在 C++ 中就可以对其进行运算符重载。

    element-type this[int index] 
    {
       // get 访问器
       get 
       {
          // 返回 index 指定的值
       }
    
       // set 访问器
       set 
       {
          // 设置 index 指定的值 
       }
    }
    

      注意: 索引器可以声明为多个参数,参数类型也可以为其他类型,比如字符串;

    3.5 委托 Delegate

      C# 中的委托类似于c/c++中的函数指针,委托让 C# 中的函数成为第一类对象,可以作为参数和返回值来进行传递,在实现事件和回调方法时特别有用。在 Java 中需要借助 Function 接口来实现此类功能。

      声明委托,也类似于 c/c++ 声明函数指针:

    delegate

      比如,声明一个带有单个 string 参数且返回 int 值的方法的委托:

    public delegate int MyDelegate (string s);

      委托通过关键字 new 来实例化,

    MyDelegate a = new MyDelegate(TargetMethod);

      委托可以多播!与事件处理有很大关系!!

      委托在使用形式上比 Java 的 Function 更简洁,更流畅一些。

      匿名方法:是一种无名的委托对象,将代码块赋值给匿名委托:

    delegate void NumberChanger(int n);
    ...
    NumberChanger nc = delegate(int x)
    {
        Console.WriteLine("Anonymous Method: {0}", x);
    };
    
    
    void change(int x)
    {
        ...
    }
    
    NumberChanger nc1 = new NumberChanger(change;
    

    3.6 事件 Event

    • 发布器: 管理事件与订阅者的映射关系,并发布事件到器订阅者;
    • 订阅器: 又称为监听器,处理器等,接收一个事件,并处理

      事件声明:

    public delegate void BoilerLogHandler(string status); // 声明事件的委托类型,也就是定义 handler
    public event BoilerLogHandler BoilerEventLog; // 定义事件
    

      使用事件的步骤:

    1. 实例化发布器
    2. 实例化订阅器
    3. 使用订阅器的方法来实例化发布器的委托
    4. 将实例化的委托添加到发布器事件中

    3.7 集合 Collection

      集合类是专门用于数据存储和检索的类,根据结构可分为 Stack,Deque,List,Set,Map

      System.Collection 命名空间的类:

    1. 动态数组(ArrayList):它代表了可被单独索引的对象的有序集合。它基本上可以替代一个数组。但是,与数组不同的是,您可以使用索引在指定的位置添加和移除项目,动态数组会自动重新调整它的大小。它也允许在列表中进行动态内存分配、增加、搜索、排序各项。
    2. 哈希表(Hashtable):它使用键来访问集合中的元素。当您使用键访问元素时,则使用哈希表,而且您可以识别一个有用的键值。哈希表中的每一项都有一个键/值对。键用于访问集合中的项目。
    3. 排序列表(SortedList):它可以使用键和索引来访问列表中的项。排序列表是数组和哈希表的组合。它包含一个可使用键或索引访问各项的列表。如果您使用索引访问各项,则它是一个动态数组(ArrayList),如果您使用键访问各项,则它是一个哈希表(Hashtable)。集合中的各项总是按键值排序。
    4. 堆栈(Stack):它代表了一个后进先出的对象集合。当您需要对各项进行后进先出的访问时,则使用堆栈。当您在列表中添加一项,称为推入元素,当您从列表中移除一项时,称为弹出元素。
    5. 队列(Queue):它代表了一个先进先出的对象集合。当您需要对各项进行先进先出的访问时,则使用队列。当您在列表中添加一项,称为入队,当您从列表中移除一项时,称为出队。
    6. 点阵列(BitArray):它代表了一个使用值 1 和 0 来表示的二进制数组。当您需要存储位,但是事先不知道位数时,则使用点阵列。您可以使用整型索引从点阵列集合中访问各项,索引从零开始。

    3.8 泛型 Generic

      泛型允许参数化类型,在集合类中大量使用。

      使用泛型是一种增强程序功能的技术,具体表现在以下几个方面:

    1. 它有助于您最大限度地重用代码、保护类型的安全以及提高性能。
    2. 您可以创建泛型集合类。.NET 框架类库在 System.Collections.Generic 命名空间中包含了一些新的泛型集合类。您可以使用这些泛型集合类来替代 System.Collections 中的集合类。
    3. 您可以创建自己的泛型接口、泛型类、泛型方法、泛型事件和泛型委托。
    4. 您可以对泛型类进行约束以访问特定数据类型的方法。
    5. 关于泛型数据类型中使用的类型的信息可在运行时通过使用反射获取。

    3.9 多线程

    System.Threading

    3.10 Iterator

      直接 yield return

    public static System.Collections.IEnumerable SomeNumbers()  
    {  
        yield return 3;  
        yield return 5;  
        yield return 8;  
    }
    

      通过循环来 yield return

    public static System.Collections.Generic.IEnumerable<int>  
        EvenSequence(int firstNumber, int lastNumber)  
    {  
        for (int number = firstNumber; number <= lastNumber; number++)  
        {  
            if (number % 2 == 0)  
            {  
                yield return number;  
            }  
        }  
    }  
    

      创建 Collection类: foreach 语句会隐式调用 GetEnumerator 方法

    public class DaysOfTheWeek : IEnumerable  
    {  
        private string[] days = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };  
    
        public IEnumerator GetEnumerator()  
        {  
            for (int index = 0; index < days.Length; index++)  
            {  
                // Yield each day of the week.  
                yield return days[index];  
            }  
        }  
    }  
    

      yield return 可以在 method 或者 get 访问器中调用。尽管 iterator 的定义像个方法,但其实编译器会将其转换为一个嵌套类(nested class),本质上是个状态机。这个类会在 佛reach loop 中跟踪 iterator 的位置。

      可以通过 Ildasm.exe 工具去查看编译器为 iterator 生成的中间代码。

    3.11 表达式树 Expression Trees

      简单来说就是语法树,通过树形结构的节点来存储表达式。通过表达式树可以动态修改可执行代码。

      下面的代码展现了如何通过 API 来创建 lambda 表达式对应的 Expression tree。

    ParameterExpression numParam = Expression.Parameter(typeof(int), "num");  
    ConstantExpression five = Expression.Constant(5, typeof(int));  
    BinaryExpression numLessThanFive = Expression.LessThan(numParam, five);  
    Expression<Func<int, bool>> lambda1 =  
        Expression.Lambda<Func<int, bool>>(  
            numLessThanFive,  
            new ParameterExpression[] { numParam });  
    

      Expression tree api 也支持赋值语句,控制语句(循环,条件),以及 try-catch 代码块。

      编译与执行

    // Creating an expression tree.  
    Expression<Func<int, bool>> expr = num => num < 5;  
    
    // Compiling the expression tree into a delegate.  
    Func<int, bool> result = expr.Compile();  
    
    // Invoking the delegate and writing the result to the console.  
    Console.WriteLine(result(4));  
    
    // Prints True.  
    
    // You can also use simplified syntax  
    // to compile and run an expression tree.  
    // The following line can replace two previous statements.  
    Console.WriteLine(expr.Compile()(4));  
    
    

    4 异步编程

    4.1 async, await

      异步/非阻塞编程,可提升应用的响应性。比如在 web 开发,以及 ui 开发上,大有益处。

      但传统的实现异步的方式都比较复杂,比如 Java 中的 nio,需要了解 channel,selector,buffer 这些概念,或者使用 netty 这样的网络框架。c/c++ 进行异步/非阻塞编程,则需要理解 select,poll,epoll 等概念。难以开发,也难以维护。

      C# 则通过引入 async,await 等关键字,让编译器去处理复杂的异步/非阻塞逻辑,让语言层面的异步逻辑清晰流畅。

      使用 async 来指定 method,lambda expression, or anonymous method 为异步。

      例如:

    public async Task<int> ExampleMethodAsync()  
    {  
        // . . . .  
    } 
    

      任何函数(方法),如果内部调用了 async 方法,那么该方法也必须声明为 async 方法,除非通过 await 关键字来调用 async 方法或者其返回结果 。

    async Task<int> AccessTheWebAsync()  
    {   
        HttpClient client = new HttpClient();  
        Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com");  
    
        
        DoIndependentWork();  
        string urlContents = await getStringTask;  
    
        return urlContents.Length;  
    }  
    
    1. 方法签名中有 async
    2. 方法名后缀 Async
    3. 返回值为 Task

      await 标明方法可以执行到何处,await 之前应该为结果无关的独立逻辑,当执行到 awati 时停止,等待异步操作完成。同时该方法被挂起,控制权返回至上层函数。

    4.2 控制流程

    这里写图片描述

    1. 一个 event handler 调用并 await 一个异步方法: AccessTheWebAsync
    2. AccessTheWebAsync 调用异步方法 GetStringAsync 去网站下载数据
    3. 当 GetStringAsync 因为某种原因需要挂起时,不会阻塞,会将控制权重新交给 AccessTheWebAsync
    4. AccessTheWebAsync 会执行它的同步代码逻辑,直到 await 语句,然后挂起并将控制权交给 event handler
    5. 当 GetStringAsync 完成时,结果会存放在其返回的 Task 对象中,await getStringTask 返回结果。

     async 方法是非阻塞的,await 表达式并不会使当前线程阻塞,它只是标注挂载点并将控制权转移至调用方。async 和 await 关键字并不会去创建额外的线程,异步机制并不是通过多线程来实现的。

    展开全文
  • C#急速入门

    万人学习 2019-03-09 23:06:46
    C#语言系列课程分为:1.C#急速入门2.C#之面向对象观看地址:https://edu.csdn.net/course/detail/266413.C#高级进阶 观看地址:https://edu.csdn.net/course/detail/31065 4.程序员内功修炼 - 数据结构(C#)观看地址...
  • C#语言的概述

    万次阅读 2016-11-17 16:15:46
    C#开发概述,以及VisualStudio 2015专业版下载安装

    C#语言的概述

    C#是微软公司推出的一种语法简单,类型安全的面向对象的编程语言,我们可以通过它编写在.NET Framework 上运行的各种安全可靠的应用程序。

    C#是C和C++派生来的一种简单的、现代、面向对象类型安全的编程语言,并且能够和.NET框架完美结合。

    特点:

    1.语法简洁,不允许直接操作内存,去掉了指针操作。

    2.彻底的面向对象设计,封装、继承、多态。

    3.与Web紧密结合,C#支持绝大多数的Web标准,如HTML、XML、SOAP。

    4.安全机制很强大,.NET提供的垃圾回收器能够帮助开发者有效的管理内存资源。

    5.兼容性,因为C#遵循.NET的公共语言规范(CLS),从而能够保证与其它语言开发的组件兼容。

    6.灵活的版本控制技术,因为C#语言本身内置了版本控制功能,因此是开发人员更容易的开发和维护

    7.完善的错误、异常处理机制。C#提供了完善的错误和异常处理机制,使程序更加健壮。


    那么肯定有些哥们会郁闷的问.NET和C#到底什么关系?

    说白了,C#和.NET是依托关系,没有.NET就没有C#,.NET框架是微软推出的一个全新的编程平台。

    从技术的角度,一个.NET应用是一个运行于.NET Framework之上的应用程序。(更精确的说,一个.NET应用是一个使用.NET Framework类库来编写,并运行于公共语言运行时Common Language Runtime之上的应用程序。)
    如果一个应用程序跟.NET Framework无关,它就不能叫做.NET程序


    开发工具的话我推荐大家使用VisualStudio 2013/2015  (WIN10兼容)。

    下载地址:VisualStudio2015专业版

    激活密钥:HMGNV-WCYXV-X7G9W-YCX63-B98R2


    界面的操作以及快捷键:这个我就不详细介绍了,大家不用刻意去记这些东西的,vs本身就是中文的,操作起来也很直观明了,开发中遇到了快捷键或者界面成操作问题,自己查阅资料,多用多记,就孰能生巧了,大家学习要有自己的方式方法。





    展开全文
  • 因为您可以用,并且也是您的最佳选择!之所以可用,是因为 C# 能够很好地在 ...之所以是您的最佳选择,是因为 C# 是编程语言创新方面的领导者,是原生跨平台移动应用程序的最佳选择,并且还有很多的优点超乎您的想...

    因为您可以用,并且也是您的最佳选择!之所以可用,是因为 C# 能够很好地在 Mac、Linux、Android 和 iOS 上运行(对了,还有 Windows);它可以在您最喜爱的编辑器上运行;它在一个稳定的企业级平台上经过了充分的时间验证;最为重要的是:它是完全开源的!之所以是您的最佳选择,是因为 C# 是编程语言创新方面的领导者,是原生跨平台移动应用程序的最佳选择,并且还有很多的优点超乎您的想象。在本次 GOTO Copenhagen 2016 大会讲演上,Mads Torgersen 邀请您一起来探索 C# 的核心,探究为什么它仍然散发着活力,并探寻未来 C# 的发展趋势。

    概述  

        我是 Mads Torgersen,就职于微软的 C# 部门。我现在年纪大了,因此我随身都穿着这件 T恤,上面印着我正在负责的项目和语言名称,以防我忘掉它们。这里我想谈一谈 C#,为什么我要推荐用它来作为大家的首选编程语言呢(即使到目前为止您还没有接触过 C#)。


    Stack Overflow - 最受欢迎和喜爱的技术

        Stack Overflow 每年都会进行一次调查,询问很多开发者们都关心的问题(当然,在很多方面这些问题都是很具有倾向性,是很不科学的)。您必须在 Stack Overflow 上才能参与。

        C# 是一门被广泛使用的编程语言(排行第四,排行前三当中有一门实际上并不属于编程语言——我说的不是 JavaScript,我说的是 SQL)。可以看出,C# 是一门主流语言。

        他们同样还问开发者们:是否还想继续使用目前正在用的语言,并让人们投票出他们最喜爱的技术。C# 同样也在这个列表当中。这说明人们都很喜欢 C# 这门语言。此外还有其他人们也喜欢的语言,但是您还可以注意到,这些语言中的大部门要么就是受众较少,要么就是非常专业化,很多都是某种狂热信仰的一部分了。在这两个列表当中,只有少数才是用途广泛、受人们高度喜爱的。很高兴能看到 C# 位于这个列表的三大最受欢迎的技术之一,其中两个是编程语言,并且* Python 也在这里面*。

        我们不断思考我们的所作所为,怎样才可能是正确的呢,怎样才能让我们在多年以后仍然喜欢它。似乎并不是所有人都用过 C#,因为很多人所在的公司已经有 10 年多的历史了,里面存在了很多的遗留代码。目前 C# 仍然保持着活力,我们希望它能将这份活力保持下去。我们同样也有各式各样的想法,而这驱动了 C# 的演进。

        我们非常渴望去演进 C#。如果您看过现代语言的演变进程的话(从少到多),就会明白我们积极保持语言现代化的目的所在了。作为参与编程语言演变的一份子,我们有些时候是推动者,有些时候是跟随者,无论如何,我们都试图让 C# 成为程序员们如今的绝佳选择之一。我们不应该搞所谓的「限定」,只局限于某几个平台,因为过去十年当中就有人这么做了,结果可想而知。

        我还想提一提 F#,因为这相当于是我们的姊妹语言,它非常受欢迎,因为它很轻巧、也很强大。F# 是一门功能强大的语言,我们在与 F# 团队的合作当中获益良多,并且它也给我们提供了很多设计灵感。

        (说明:F#是由微软发展的为微软.NET语言提供运行环境的程序设计语言。它是基于Ocaml的,而Ocaml是基于ML函数程序设计语言的。函数编程是解决许多棘手问题的最好方法,但是,纯函数编程并不适合常规编程。因此,函数编程语言逐渐吸收了命令式、面向对象的编程模式,不仅保持了函数编程范式,同时也混合了其他需要的功能,使函数编程编写各种类型的程序都很容易。F# 就是这种尝试的成功代表,比其他函数编程语言做得更多。F#主要是为了解决特定的某些复杂问题,所以本身定位使得VS没有提供F#的ASP.NET/WPF/GDI+的模板,若要使用需要自己配置。所以,一般情况下都是用C#。

     

    时代在改变 - 为什么要选择 C#

        在越来越多的场景当中,您都可以使用 C#来进行编程。我们正在努力地做出一种改变。C# 在 Windows 当中是一种很重要的主要编程语言,但同时,我们在其他平台上仍然还非常稚嫩。至少大多数平台是这样。现在 C# 已经是所有平台上可选的编程语言之一,这非常鼓舞人心,然而我们同时也有些顽固,此外这些平台上也出现了各式各样新颖的语言。这使得我们迫切地希望其他平台上也能够使用我们的语言。

        我们已经很多次对我们的语言进行了演进。实现 C# 底层的编译器和 IDE 技术(名为 Roslyn 项目)为 C# 的编程启用了独一无二的场景。其中一个好处是,我们将 C# 的核心从 Windows 和 Visual Studio 当中剥离了出来,这意味着 C# 能够很容易地在其他 IDE 当中使用。您可以用自己喜爱的 IDE 或者编辑器来编写 C# 代码。

        我们已经将 C# 从完全的专有技术转变为了完全开放源代码的技术了。这意味着每个人都能给 C# 贡献代码了,当然也已经很多人参与到这个项目当中来了。我们现在正在同社区展开交流,现在 C# 的演进非常迅速。因为现在这更像是一个协同项目了,而不是「微软说怎样就怎样了」。这非常让人兴奋。现在语言的变革已经不再是三年才一代了。「这是我们努力的成果,希望您能喜欢它」,我们现在每天都在与社区讨论未来的方向问题。我们随时随地都能够在网上、Github 上得到反馈。因此,我们语言设计的质量也越来越高。

        让我们从 C# 的各个项目开始一一介绍。


    无处不 C# - Xamarin

        Xamarin 以前是一家独立的公司。我们六个月之前收购了他们。这是一种使用 C# 来构建跨平台应用的技术,用来制作原生的 Android 和 iOS 应用。它可以让您使用相同的语言、相同的源代码来构建绝大多数应用组件,从而能够为多种不同的移动平台编写应用。

        它适用于 iOS 和 Android,同样也可以用在 Mac 之上,顺便提一下,Windows 也可以使用。它可以创建高品质的原生 UI。有许多大型应用正在使用这门技术,因为它可以极大地减少单独在这些平台上编码的工作量。它也允许您使用与后台相同的语言,例如说 Java,不过 Swift 和 Objective-C 还未支持。它以支持的平台量取胜,是一门实现应用的绝佳语言。

        它基于 Mono 项目,这是多年以前从微软离职的员工所实现的开源项目,并且一直维护,致力于能够在其他平台上也能够使用 C#。虽然在微软当中的我们有些固步自封,但是他们却在我们之前看到了 C# 跨平台的潜力,并实现了这个伟大的跨平台项目。Xamarin 正是基于此而生的,您在 iOS 和 Android 应用商店当中看到的许多应用都是基于 C# 的,要么是使用 Xamarin,要么是使用 Unity,这应该是业界领先的游戏引擎。


    无处不 C# - Unity

        Unity 也是一个基于 Mono 的项目,它的 2D、3D 游戏引擎是用 C# 来编写的。有很多游戏是用 C# 编写的。


    无处不 C# - .NET 核心

        在微软,我们正努力完善 .NET 核心,这是对整个 .NET 技术栈、运行时以及代码库等内容的全新实现,旨在保证轻量、并且可供服务端使用,并且可用作云和服务器工作负载。它是跨平台的,适用于 Linux、Mac 和 Windows。我们在此之上还放置了 ASP.NET 框架,这是一个被广泛使用的 Web 框架,目前您就可以在非 Windows 的机器上运行 ASP.NET 了,并且它还完全开源了!为什么我们要建立一个单独的核心呢?这将有助于您能够构建更轻量的服务器。

        首先,我们移除了 UI 框架,但是 UI 框架能够独立部署。例如,您可以将运行时环境同代码一并发布;云端无需安装各式各样的依赖文件。它拥有一个更优秀的架构,更适合微服务的部署。它同样也致力于使我们的服务端平台更加现代化。这些不同的 .NET 运行在不同的平台上,如果没有统一的部署,那么随着版本的扩散,一切就会变得非常的混乱,尤其是您作为第三方库提供方的时候。您需要某种东西能够跨平台运行,以便解决您的问题。

        我们同样也实现了一个名为 「.NET 标准库」的东西,我们提供了一个所有 .NET 平台全兼容的 API。如果您需要使用它的话,您可以直接在工具库当中链接这个 .NET 标准库即可,它将可以在所有平台上运行。您也可以收回在 .NET 生态系统中随处可用代码的能力。我们将随时对标准库进行升级,包括引入新的核心基本库,这样您任意链接所需要的标准库即可。因此 C# 能够在很多地方运行,希望这能够说服大家来尝试 C#,因为这比以前有着更大的适用范围。能够实现这个着实让人兴奋。


    Roslyn - C# 语言引擎

        我想要多谈论一些底层的内容,也就是谈一谈 Roslyn 项目。

        我们对 C# 引擎进行了现代化。以前只有一个简单的 C# 编译器。它使用 C++ 编写的,之后我们有了 Visual Studio,然后将 C# 集成了进去。然而这两者使用 C# 的方式都不同,没有任何的代码共享,因此也没有办法知道对方的相关信息。如果有人想要使用 C# 相关内容的话,那就需要为之编写一套工具,或者为它们自己的 IDE 来添加支持,这是一个很大的工作量。因为人们不得不重头开始编写,因为 C# 引擎对它们而言是个黑盒。这对我们来说也并不是让人满意的。

        因此我们决定,是时候重写编译器了,我们不仅重写了 C#,并且还采用了一些新的架构。用来实现 C# 语义的工具只能有一个。我们需要构建一个大家都可以使用的工具,以便满足他们想通过 C# 实现某些功能的愿望。这个工具与平台无关,无论是什么样的平台,比如说批处理过程、编译器,还是某些类似 IDE 的交互式环境,都可以使用这个工具进行。这是一个很难的目标,它花费了我们大量的时间来实现,并且也投入了大量的人力。但是现在,我们推出了 Roslyn API,它切实满足了我们所设定的目标。

        大家都需要知道,绝大多数 C# 工具已完成 Roslyn 引擎的迁移,不过仍然有一些没有。场下还有一位演讲者 Ted Brangs 的项目就是例外,因为他是出于某些技术原因的考虑。我们的想法是,这里是您需要用于实现 IDE 和编辑器的代码库。如果您需要使用不同类型的分析工具,那么可以导入它们来对代码中的问题进行分析。如果您想要对代码进行操作的话,例如代码迁移、代码补全或者重构之类的操作,那么您也可以使用它。如果您需要生成源代码,那么您也可以使用它。如果您需要实现更多交互式场景,例如脚本或者 REPL(比如说现在我们在 Visual Studio 当中包含了一个 C# REPL,它是在 Roslyn 的基础上构建的),那么这个引擎仍然能够编译代码并完成输出。

        这里是您所能够实现的一个范例,也就是人们能够用 Roslyn 做些什么。这可能会导致编程语言相关的工具呈现爆炸式增长,因为人们现在可以更快地来对 C# 进行处理了。它能够与 C# 很好地协同工作。现在您已经有很多可以轻易得到的信息了,比如说语法、语义等内容,您就可以按照自己的想法,向所需要的地方添加特定的位码了。有一个社区项目充分利用了这点,那就是 OmniSharp。

        (请记住:C#语言引擎--Roslyn


    OmniSharp - 随时随地可编辑 C#

        OmniSharp 是一个特别的项目,旨在让 C# 能够在您喜爱的编辑器上运行。他们实现这个功能的方法很聪明:由于 C# 现在已经可以在任何地方运行了,因此他们采用 Roslyn C# 引擎,然后在一个单独的进程中运行,不管您在进行开发的机器是什么(例如一台 Mac)。他们使用一个单独的进程来运行引擎,然后剩下所需要做的就是添加一个很简单的集成层,然后加入到特定编辑器中的集成层当中,这样双方便可以通过进程来进行通信,从而让编辑器了解到 C# 的全部信息。

        每次您按下了一个键,例如输入了点语法,然后这个时候您需要显示代码补全,这个时候它就会询问旁边的进程:「用户输入了点语法,那么我需要在代码补全列表当中显示什么呢?」。Roslyn 知晓所有的语义,它随后会告诉编辑器:「这五种方法是可用的,显示它们即可」。

        通过这种分离方式,使得所有的语义分析过程被包裹在单独的进程当中进行,然后通过标准的数据传输方式来进行数据的交换。这使得我们可以在很多的编辑器当中去实现表现良好的 C#,并且还可以提供语义感知功能(当然,这种做法褒贬不一)。

        我需要再提一点,对于微软的 Visual Studio 而言,我们使用 OmniSharp 来实现其 C# 模式,因为这是一个扩展,可以在任何地方加载。它不会内置在编辑器当中。C# 就像其他语言一样,对 Visual Studio 而言就是一个扩展组件。

        (个人认为:OmniSharp项目对Roslyn引擎进行了封装,以更方便的使第三方编辑器调用,比如自己开发一个C#代码编辑器

     

    演示 - Roslyn 分析器

        让我们举一个更具体的例子。为了帮助人们将重点放在语言实现之外的地方,我们创建了这个框架,名为 Analyzer,通过它可以轻松地对人们的源代码进行分析、诊断,最后输出结果。这样,我们便可以提供代码修正建议了。

        如果您需要:   

        1、您的组织有需要强制执行的代码格式
        2、经常执行重构
        3、想要与大家分享代码
        4、需要让代码修正自动化

        那么这个工具正是您所需要的。

        这个项目您可以在 Visual Studio 当中安装,然后就可以开始使用了。当您打开某个项目的时候,它就已经自带了为这个项目而建立的样板代码。具体而言,当您的项目像这样进入调试模式的时候,然后分析器便会提取您的代码,然后进行代码修正,最后将结果输出。分析器可以以批处理代码的方式运行,也可以将其作为 Nuget 包进行分发。它是以 Visual Studio 扩展程序的身份出现的,在 Visual Studio 的完整版本当中,它是作为调试模式的一部分运行的。现在我运行了 Visual Studio,然后它便开始执行代码修正了。这个是我在完整版本当中的 Visual Studio 所编写的操作。

        现在让我们在这个完整版本的 Visual Studio 中打开一些代码。我还没有完全实现完这些分析器的功能。这里是一些我们想要进行操作的示例代码。出于简便起见,我想要实现的东西是语法分析,这里我可以定义各种各样的语义规则。Roslyn 引擎提供了完整的信息供我使用,我可以定义 if 或者 else 语句当中没有柯里化(curlies)语句是非法的代码样式。

        我们需要实现那种老式的、固化的代码风格,也就是始终需要添加柯里化的语句,因为接下来编辑代码的时候,并不会得到太多的 BUG。我们需要在某些情况下阻止这种代码的出现,出于时间考虑,我这里只对 if 进行实现,我们当然也可以将其应用到 else 规则当中来。这里让我们来实现一个小型的代码分析器。

        这里我不会停止使用这个完整版本。我需要放置一个断点。每当我们看到 if 语句的时候,最开始需要做的就是要注册它,我们需要调用这个方法 AnalyzeNode。每当 Visual Studio 中的源代码分析器命中了一个 if 语句,那么就会自动前往这里,然后我就可以执行一些操作了,随后它就会继续分析代码,直到命中下一个断点。现在我能够得到这段代码当中的全部信息了,接下来我就可以添加操作了。我得到的东西是一个 context 对象。

        让我们看一下这个 context 当中的内容。如果这个 if 语句不符合要求,我就可以报告一个诊断过程。我可以得到当前语法树的相关节点,通常就是这个 if 语句当中的内容。让我们开始处理吧,我们将鼠标悬停在这个上面,由于我们位于调试模式,因此这里可以看到一个实际传入的对象。我们可以看到这里的确就是一个 if 语句。让我们使用 Roslyn 构建的对象模型,将其转换为 if 语句模型。

        这里我能够得到一个语法树节点,它恰好是 IfStatementSyntax 的派生类。我们可以声明 var ifStatement 赋值为该值。现在这就是我们之后唯一所需要调用的对象了,我这里将不再检查它是否是一个 if 语句。如果这个语句内部的东西不呈现柯里化的话,那么这个东西将被称为 Block,这就说明这段代码是不符合规范的。如果它不属于 SyntaxKind.Block 的话,接下来我就会提示错误了。我会告诉用户:「这里不对」。现在我需要汇报诊断结果。不过现在我还没有实现,我需要进行一点重构操作,来为之生成一个局部变量。

        我可以通过 Diagnostic.Create 创建一个诊断,它需要我提供一些参数。首先是一个被称为 Rule 的描述符,然后我需要指定 location。也就是当问题出现的时候,我需要在代码当中显示波浪线。然后我需要指明当前违背了何种规则。然后指明不符合规则的位置。让我们再对这段实现进行一下重构,生成一个局部变量。这就是我在调试模式全部所需要做的。

        那么什么是所谓的「位置」呢?也就是我当前正在处理的这个节点:if 语句。那么我们需要在那里放置提示信息呢?让我们放在这个 if 关键字上吧。if 语句这里拥有一个 if 关键字,因为这是一个具体的语法树。它拥有里面代码的全部实现细节,包括所有的位置。让我们从中取得相关的位置。这里通过 GetLocation 方法来获取。我们得到 if 关键字的位置,然后将这个位置传入到这个方法当中。我编写了一些代码。让我们移除这个断点,然后继续在调试器当中运行。我们等待一会儿,看看发生了什么,好的,现在您会看到 if 语句当中出现了波浪线。

        这就是我的全部操作:编写三四行代码就可以识别出问题所在,并告诉框架在哪里显示这个问题。为了向您证明它能够起作用,我把这段代码注释掉,您会发现现在波浪线消失了。

        当您试图实现更为复杂的操作的时候,就变得有点困难了,但是这仍然是一个相对简单的语言模型,因为它包含了完整的语法和绑定语义,人们可以用它来构建工具,然后与别人分享,这样便能够让每个人在编辑 C# 的过程当中遵循一致的原则,不管它们所用的编辑器是什么,只要是基于 Roslyn 的就行。无论人们位于哪个平台,他们都能够从中收益匪浅。

        我写的这个分析器同样可以在批处理模式当中运行。它可以成为编译过程当中的一部分,可以标记警告或者错误,就如同编译器所做的那样。我还可以实现修复工具(但我之后的时间不打算演示这个功能),它可以基于我们制定的规则对代码进行修复。
        这就是 Roslyn 这边的演示,它是如何帮助人们获得更好的编码体验的,一个更好的 C# 开发体验。它给予了我们更好的代码库,更好的架构,显然在 C# 当中,我们可以对它进行 Dogfood 测试,以更好地帮助我们演进语言本身。


    C# 的演进

        如今我们对 C# 进行演进较以前已经容易很多了,并且我们可以让社区通过贡献代码而参与到 C# 的演进当中来。然而,这些演进的版本(我不会把所有版本都列述一遍)——展现了我们在创新过程当中的破坏性。

        我想以 Async 为例。我们编写了 LINQ,也就是我们在 C# 版本 3 的时候引入的查询操作。我们采取了一个很有趣的冷门语言所存在的概念,并尝试将其主流化,将这些概念引入到 C# 这个主流语言当中,从而帮助它们开扩更广阔的市场。C# 当中的 LINQ 查询就是您能够在其他函数式编程语言当中找到的一个例子。

        我们把它们与 Lambda 表达式结合在一起。现在世界上绝大多数语言都可以使用 Lambda 表达式。当然几年以前这并不常见。如今 Java 也可以使用 Lambda 了。当然,我们还是回到 C# 版本 2 来,在这个版本中我们引入了泛型,仅仅只是慢了 Java 一拍,但是泛型已经成为了 C# 必不可少的一部分。因为在 C# 当中,泛型是深嵌入运行时当中的。Java 则是采取了比较谨慎的方法,让泛型直接编译成所需要的东西。

        当您将泛型机制实现在运行时当中的时候,这对获取语义而言是 100% 有好处的,然而这同样也意味着性能特性将截然不同,尤其是当语言中存在值类型的时候,当 C# 从版本 1 升级的时候就遇到这个问题,Java 可能会在未来采取这种方式来实现泛型。当语言当中存在值类型的时候,您希望泛型能够识别出它们,并且专门为这些值类型设定特定的规则,也就是在使用泛型的时候就无需对其进行封装和分配内容空间。这样泛型就能够让代码更快,而不是产生拖累。

        自我们升级之后,泛型便成为了很多语言的标配特性。由于泛型的引进,我们借此便能够正确地实现查询功能。由于泛型是深嵌入在运行时当中实现的,因此我们可以使用反射机制,这样我们便可以实现一些奇怪的代码引用,然后将 C# 代码转换为 SQL。这都是基于类型可以变换的机理才得以实现,并且甚至在运行时都是可以如此使用。

        我们将动态值集成到了静态类型的系统当中,这种类型的类型是动态的、变化的,我们称之为 Dynamic。再次强调,其底层实现仍然是基于泛型来实现的,这使得其运行效率高效,并且避免了很多无谓的封装操作。Async 则是深度依赖于泛型机制。在 C# 版本 6 当中,我们引入了 Roslyn,因此对于实现任何特定的语言特性而言,不再是一件难事。我们现在拥有了更多的灵活性,现在我们便可以实现那些还未实现的微小特性了,我们通过实现这些特性,可以使得开发工作更简单、更优雅、更简洁、更轻松。

        之后我们在 C# 版本 6 当中引入了 swath ,也就是现在的 C# 版本。然后在之后的 C# 版本 7 当中,我们将再次引入一些更重要、更底层的特性,我们想要从函数式编程语言当中进行大量借用特性,我认为我们下一步可能是需要引入相关的特性,来处理那些不必用面向对象的方式处理的数据。大家都知道我们一开始是一门非常纯粹的面向对象语言,然后只是倾向于添加一些函数式的特性来作为面向对象的一些扩充,并且我们也在尝试将这两者很好地结合起来。这个灵感来自于 Scala,并且 JVM 也在这么做,尝试将函数式和面向对象结合起来,但是我们绝对不会抛弃面向对象这个根本。

        (Scala是一门多范式的编程语言,一种类似java的编程语言,设计初衷是实现可伸缩的语言,并集成面向对象编程和函数式编程的各种特性。


    演示:Async

        我打算跳过这个 Async 的演示,因为大多数人可能都知道它的作用是什么了。那么让我们来谈一谈即将到来的 C# 版本 7。

        (C# 1.0 with Visual Studio.NET
           C# 2.0 with Visual Studio 2005
           C# 3.0 with Visual Studio 2008,2010(.net 2.0, 3.0, 3.5)
           C# 4.0 with Visual Studio 2010(.net 4)
           C# 5.0 with Visual Studio 2012(.net 4.5),2013(.net 4.5.1, 4.5.2)
           C# 6.0 with Visual Studio 2015(.net 4.6, 4.6.1, 4.6.2)
           C# 7.0 with Visual Studio 2017(.net 4.6.2, 4.7)
           C#版本是VS版本决定的,也可与相应的.net framework版本对应起来


    C# 版本 7

        让我们从元组 (tuple) 开始。首先这里我有一个完整的程序。然后里面有一些数字值。因为数字是非常容易理解的,但是可能不是所有人都能够知晓其中的含义:我们现在拥有的是二进制的字面量。这是一个很微小的特性。当您教孩子编程的时候,这就非常有用了,这些位于数字下方的则是位 (bit)。我现在要再添加一个。我们这里同样还有数字分隔符,就像其他语言所做的那样,您可以将这些分隔符放在需要的地方,从而让数字更容易阅读。

        我这里打算实现一个名为 Tally(计数器) 的方法,它将数组当中的数字累加起来,得出计算结果。这样我们便可以对这些数字调用这个 Tally 方法。当然目前这个方法我还没有实现,让我们使用重构来生成这个方法。这是一个静态方法。目前它的返回值为 Void。或许它应该返回其他的东西。我觉得它应该要返回这个累加值,或者直接返回数字的总数?我觉得两者都是非常重要的。但是现在在 C# 当中您只能返回一样东西,但是在不久的将来,您就可以返回两个返回值了,甚至三个、四个、更多。只要您想,您实际上可以创建一个超大的元组,但是这可能是个糟糕的主意。

        现在让我们返回两个 int 值。这是一个元组类型。它表示里面有两个 int 类型,这应该很容易理解。这里是元组字面量,我们还是先返回一些虚拟的值。这里面包含了一些所需的值,通过括号和逗号包裹起来,当然这个语法应该比较正常。当我使用这个方法的时候,我可以获取它的返回值,然后我会发现我得到了一个元组类型。

        那么我们该如何使用元组呢?让我们将其输出出来。插入字符串。总和可能位于这里的第一个位置。让我们来看一下元组有些什么:Item1 和 Item2。很显然,我们知道它们分别代表了什么,我们可以直接使用这两个名称。虽然这个名字比较糟糕,但是能用就行。C# 当中的元组还可以为不同的元素赋予不同的名称。这里我将指定各个元素的名称。这是什么意思呢?

        当我获取到这个元组的时候,它便可以告诉我它里面的元素是什么。这同样也意味着我来到这里,输入点语法,就可以看到这些预览而已;最终的版本应该需要隐藏掉这些糟糕的名字。这里我们会看到拥有了很显然的名字,因为这里您可以看到 sum,我们可以直接使用它来获取元组当中对应的值。之前那些是底层当中的真实名称,但是编译器知道跟踪这些别名,并使用它们来替代显示。

        元组当中拥有元素别名是非常重要的,因为您很可能记不住这个元组是姓在前还是名在前。因此元组需要提供这些信息,这样才能够让人容易理解。您需要有获取别名的能力。

        当然,您很可能会希望在获取到元组的时候,就立刻将其解构,将元组当中的值分开,当然您也可以在 C# 当中做到这一点。您可以在这里声明 sum, count,然后元组便会立刻解构为 sum 变量和 count 变量。这样我们便可以不再使用 t. 前缀,而是直接使用 sum 和 count。

        让我们现在来实现这个方法。这里我们不再返回一个虚拟值,让我们返回一个真实的结果。这里我们对这些数字执行 foreach 操作;这里我们将其称为 values。接下来我们在每次遍历的时候更新结果值。

        result 这个名字太长了,我想将其命名为 r。让我们声明 r = 这个新的元组字面量。这里我希望能够获取旧有的值。我希望 r 同样也有元素别名。让我们前去给其增加别名。您可以在元组字面量当中为其赋别名。这里的语法和命名参数所做的相同。现在 r 拥有了 s 和 c 两个元素别名。我们可以调用 r.s,便可以在这里获取到之前的总和值,然后加上新的值 v,然后这里的 r.c 总数需要加 1。

        您可能会在想,这不是很复杂么,很浪费空间。这不是每次都直接分配一个新的数组?或者说在每次遍历的时候偶会创建一个新的元组么?这样做的话,在资源受限的设备或者需要花钱的云端当中是不是很不好?为这些元组分配内存空间是不是非常浪费?

        这并不会导致空间的浪费,因为元组不属于对象。元组被实现为值类型,是以 C# 当中的结构体实现的。因此它们不会分配内存空间。它们只是直接更新某些在堆上的东西。这些值类型是使用 copy 来传递的,而不是通过引用来传递。元组没有标识,它们当中仅仅只是包含值而已(我觉得元组应该是这样的)。它们应该只是短暂的存在。因此它们不应该拥有生命周期,这样才能更有效率。

        元组不仅是值类型,它们同样也是可变类型。我知道在函数式阵营当中的人们会很反对这种做法,但是我还是坚持元组是可变类型。您可以修改元组里面的值。而不是这样子写:r.s += value。作为一个单独的语句 r.c++ 就很好了,就不用更多的重复了。此外我还可以交换元组当中元素的位置,这并不是危险的操作,因为在线程之间没有共享的可变状态,因为这是一个结构体。没有对象去共享它。您可以随意将其传递到任何地方,它是用拷贝操作执行的,不存在危险的情况。

        为什么我们总要强调面向对象呢?为什么一切都必须要封装起来呢?元组没有属性,仅仅只是字段。它们是包含某些可变公共字段的结构体。获取非常简单,您可以很轻松地明白自己的做法。这就是元组的正确用法,因为它们不是抽象类型;它们不会封装任何东西——它们仅仅只是值而已。

        关于元组的其他几件事是:由于元组是一种类型,因此它可以判断相等。例如,您可以将元组作为字典当中的键来使用。如果您想要让两个类型都作为某个字典的键,那么使用元组是再好不过的,这样一切都相安无事。哈希值和其他所用的东西在数据结构当中都能够正常的工作。

        当然,这也是从异步方法当中获取多个值的绝佳方法,因为如果操作的是异步的话,您可以返回 Task 的元组,这样当所有的操作结束之前,您就可以依次等待。得到元组之后,就可以对其解构并继续前进。元组是很好的传输工具。对于 async 方法以及其他方法而言,如果有多个返回值的话是非常糟糕的,因为您没办法输出多个参数,但是现在通过元组您可以实现这个操作了!

        (如果需要使用同一类型的多个对象,可以使用集合和数组;如果需要使用不同类型的多个对象,可以使用元组(Tuple)类型。.NET Framework定义了8个泛型Tuple类和一个静态Tuple类,它们用作元组的工厂。元组用静态Tuple类的静态Create()方法创建。Create()方法的泛型参数定义了要实例化的元组类型。


    未来展望:更多的模式

        我们开始向 C# 当中添加模式匹配 (pattern matching)。

    复制代码

    1 if (o is Point(5, var y)) { WriteLine($"Y: {y}"); } // 递归模式
    2 
    3 state = match (state, request) // 匹配表达式,匹配元组
    4 {
    5     (Closed, Open) => Opened,
    6     (Closed, Lock) => Locked,
    7     (Opened, Close) => Closed,
    8     (Locked, Unlock) => Closed,
    9 };

    复制代码

        这里我们从函数式阵营当中引入了一个全新的理念,我们正在逐步实现这个功能。您会在未来的 C# 版本当中见到更多的内容,但是现在让我们跳过这里,介绍一下第一种模式。

        让我们把这个例子变成包含递归数字列表的情况。这里我们用的不是 int 数组,而是一个对象数组,其中我们有一个约定,其内部的东西是 int 值或者是其他包含 int 的数组,也可以是新的对象数组,其中有一些 int 值嵌套在当中。或许如果里面也可以包含 null 可能会让人能更加明白,现在我们需要更新一下我们的这个 Tally 方法,让其能够处理这个数组。

        首先让我们直接替换为这个对象数组,好的现在我们得到了一个错误,因为这个 v 不再是 int 类型了;他是一个对象。我们需要知道它是否是 int 值,如果是我们就添加它。因此我们需要进行一些逻辑处理;在过去,我们会执行一个类型检测。如果 v 是 int 类型的话,然后我们就执行转换并处理;但是,即便我们检测出它是 int 类型,这里我们实际上仍然不知道它是什么。我们必须再次执行检查才能将其放入。

        相反在这里,您可以将其认为是对 is 表达式的一个扩展。您现在可以声明一个变量。当您询问它是否 is int 的时候,如果是,那么就会取这个 int 值并将其赋到这个新的变量 i 当中。接下来变量 i 就有 v 的值了,但是类型已经确定为 int 了。现在我们就可以在这里将其添加进去,运转良好。

        is 表达式现在扩展为允许模式的存在了,这是 C# 当中引入的一个新概念。模式,而不是类型。模式可以是很多复杂的组合。现在模式还不能很复杂。基本上只能够允许常量或者类型模式。例如,可以设定常量值 v is 7(现在这个被允许了,因为这属于常量模式)。我们正在实现更多的模式,将它们集成到语言特性当中来,比如说表达式。

        另一个我们正在集成的地方是,我们正在尝试将其整合到 switch 语句当中。我现在可以对任何东西进行 switch,而原来 swtich 只可以对原子类型进行操作。这是很古老的特性了,不过现在它可以对任何东西进行操作了。我们可以对对象进行操作:switch on v。在我的这个 switch 语句当中,我可以列举没有任何常量存在的情况,现在这个属于一种特殊的模式,不过可以对任何模式进行操作。我可以这么声明 case int i。(我必须记得要 break,这就是为什么在这里我得到了一个波浪线)。

        我这里已经用了一种模式。我扩展了 switch 语句当中了 case 块,以便其能够应用某种模式,并且可以「当这种模式适用时,就执行此 case 块」。我可以对 swtich 语句进行现代化。我可以让对象数组成为 case 的条件,这也是我所期待的另一件事。让我们将其声明为 a,我可以将条件放到 case 里面。我可以设定「我只需要长度大于 0 的对象 a,因为 a.Length 大于 0(否则就不必执行其他操作了)」。在这种情况下,我可以设定 var t = Tally,然后加入嵌套数组,并将结果添加到 r;r = r。您知道后面的用法:r.s + t.sum、r.c + t.c。然后 break 退出。这是对既有模式特征的一种泛化,也就是 C# 当中模式匹配所拥有的程度。

        在未来,我们希望能够加入更多的模式。我们需要更智能的模式。您应该需要能够使用递归模式。我们让您能够指定一个给定的类型,让其能够被解构。例如,您可以在 Point 类型进行指定,这样它就可以被解构,就像我们之前对元组进行解构,分解为不同的变量里面。当类型被设定为可解构的之后,我们就将其与模式匹配结合在一起,并允许您能够:同时检查 o 是否是 Point 类型,如果是的话就对其进行解构,并且可以应用递归模式:如果 o 是一个 Point,那么这个点的第一个部分 x is 5,然后将第二个部分放到变量 y 当中。您可以得到更智能的模式。您也可以使用它来构造不可读的代码,但是一般而言,如果能够更深入模式,那么您就会发现模式是非常有用的。

        我们应该需要在新的地方当中添加模式。switch 语句是 20 世纪 60 年代的产物了。或许我们可以新增一个 switch 语句的表达式版本。或许是一个匹配表达式,而这是函数式语言当中所称呼的,它具有更新的语法,基于表达式,然后 case 语句中也可以添加表达式,这样可以让代码更为简洁。但是现在我们已经有了模式的概念,我们可以添加新的模式,然后向新的地方添加新的模式。这就是我们下一个版本的 C# 所需要关注的一件事,我们已经在努力实现它们,因为 C# 版本 7 已经差不多完成了。(我们还没有发布,也不要问我什么时候发布)。

        (此部分关于C#新版本模式的概念理解起来比较模糊,还是待以后版本发布后实际使用一下体现会更贴切。


    未来展望:可空的引用类型

    复制代码

    1 string? n; // 可空的引用类型
    2 string  s; // 不可空的引用类型
    3 n = null;  // 允许;它是可空的
    4 s = null;  // 警告!不应该为空
    5 s = n;     // 警告!类型不同
    6 WriteLine(s.Length); // 允许;是不可空的
    7 WriteLine(n.Length); // 警告!它可能为空
    8 if (n != null) { WriteLine(n.Length); } // 允许;您进行了类型检查
    9 WriteLine(n!.Length); // 如果存在的话当然可以

    复制代码

        新的语言当中,有一个特性正在成为主流,那就是类型系统能够进行区分的能力,也就是判断类型是否可空。

        变量有时候可能会为 null,因为它是值域的一部分;但是有些时候我并不希望空值出现,那么为什么我需要随时对引用错误进行处理呢?Swift 也有这项功能。我们能否让 C# 也实现这些功能呢,即便我们现在已经推出了 7 个版本,而可空性完全是一个基于运行时的玩意儿呢?

        我们认为可以:我们已经在 C# 当中为可空值类型留下了尾随问号标志。如果我们允许您将它应用于引用类型,或许这就是您陈述某个类型为空的方式。另一方面,如果您不这么声明的话,就说明您期望那里的东西不可能为空。

        我们将帮助您进行维护,这意味着我可以将 null 分配给 n,但是不能够分配给 s,并且如果没有任何限定条件的话我也无法将 n 赋值给 s,因为 n 的值很可能是 null。我保护变量以防止它持有不该持有的值。另一方面,当我想要使用这个引用的时候,我可以无需任何限定就执行 s.Length,因为我们知道它可能不会为 null。我们无法让像 C# 之类的语言做一个保证,保证这里一定有值。

        n.Length 会警告您它的值可能是 null,您可能会得到 null 引用异常。解决的方法是,这些新语言当中存有一种新的空值检查特性。它们有一种新的模式匹配方法(或者某种可以用来检测 null 的东西)。我们不打算改变您检查 null 的方式。在 C# 当中,已经有 7 种检查空值的方式存在了。相反,我们想让编译器对其进行跟着,来检查某个类型是否为空。

        如果您有一个 if 语句,来判断 n 不为空的时候才进入到其中,那么我们就知道这个范围已经经过了类型检查了。事实上它的值不可能为 null,我们将会假设您使用点语法访问内部成员是没有任何问题的。那么有没有别的办法处理它呢?当然有,然而您现在仍然还需要使用这种方式。您必须要随时使用这种方法才能消除所有的空值引用异常。

        此外还有一个「强制」操作符,您可以给某个可空值上面加一个前置感叹号 (!),这就意味着您强制让其不能为空。您知道在这里,它的值永远不可能为空,只要你能足够勇敢、足够肯定,那么您就可以使用点语法,也就没有警告的产生。我们已经在开发这个功能,我们希望能够在下一代 C# 当中得到这个功能。

       希望这个功能是非常有用的。关于这个特性的一件趣事是:它不仅需要深入到语言内部进行调整,还需要确保我们所有的框架都应用上这个特性,这样您才能够确保自己的代码应用上了正确的可空值。这是一个非常具有挑战性的功能,我觉得这是非常值得的。

       (个人见解:微软在下一个C#版本中增加此定义, 目的还是为了代码的安全性。现在的引用类型在定义时并没有如此分开定义声明,以后在定义如string s这种定义时,可潜移默化的表示是不可以为null的,这样一方面可以不用进行if(s==null)这样的判断;另一方面也同时保证了在忘记进行此类判断时,程序也不会“抛出未将对象引用到定义”等此类的异常。反之,若想定义可以为null的引用类型,则可以以string? s的形式示人,算是微软在语法方面更加规范化了。

        备注:本人基于对原文的理解,增加了个人备注(紫色斜体括号部分),若有错误,请读者提出意见和看法,愿和大家一起进步!

       原文链接 by Mads Torgersen on Dec 27 2016

    展开全文
  • C#.NET是非常好的编程语言

    万次阅读 2019-02-23 15:49:13
    首先承认个人观点:C#.NET是非常好的编程语言 我接触.NET已经有三年了,虽然时间不太长,... 全球最为广泛使用的软件系统是微软的Windows 系统,而作为微软的儿子.NET语言用来开发Windows最简单的,有人说C#语言就是...

    首先承认个人观点:C#.NET是非常好的编程语言

    一、我接触.NET已经有两年了,虽然时间不太长,但是.NET给我了很大的感触,有人说.Net体系已经与时代脱节,当然,我最开始坚持的时候也有这种动摇,因为不可否认的是中国现在是Java的市场。为什么Java体系会这么火,我觉得原因就一个:便宜。开发成本便宜,服务器便宜。相较而言来说.Net为什么不火的原因就是不能跨平台啊,这套体系完全是站在了Windows的肩膀上发展起来的,脱离了Windows 他真的什么也干不了。但是这几年我突然.net有了不一样的风采,Dotnet Core起来了,完全的满足了跨平台简单方便的特点,我相信他会更好

    二. 、全球最为广泛使用的软件系统是微软的Windows 系统,而作为微软的儿子.NET语言用来开发Windows最简单的,有人说C#语言就是.NET语言,我的观点也是有点偏向这种说法,因为两种语言故由不同但是,c#的进阶可以说是.NET,并且从我的实战角度来说,小项目做过,大型项目同样做过,小项目因为时间和利润等关系来说,c#最为适合快速开发,并且做ERP来钱确实挺快的,这就不同于JAVA了,JAVA虽然有一些开源的款框架可以直接套着改,但是从我们也知道客户至上,客户是会提一些无礼的要求,那么C#这种适合快速开发的语言就非常适合来做这种项目。而大项目来说,有人说.NET后期的维护很难,确实,很难,但是.NET如果都能学会那么一切就简单了。

    三、最后,我来说一句,近几年火的语言无可厚非的有很大的炒作在里面,例如Python语言,目前中国市场最为热潮的语言,什么人工智能,大数据等等现在看起来非常火爆的专业,但是我想说python这种语言吧,貌似是做大数据最厉害的,但是吧,JAVA也能做,而且做的不比python差,甚至更好。其实Python能火的原因很大程度上源于Python是脚本语言,而且更适合与硬件做对接,可能它在机器学习上面有着很大的影响力吧,因为我没太深研究过它,我没有贬低python的意思,而是我个人原因,我不是很喜欢写脚本。

    最后说一句吧,选一门语言很重要,选一门正确的语言更重要,但是最最重要的是我能把它变成我的兴趣去学下去,而不是把它仅仅的看成吃饭的家伙,我对待我没意见对我有用的事的态度永远是:如果坚持,就要把它看成兴趣爱好,并且保持着乐观积极的态度和它玩下去。

    展开全文
  • C#语言基础原理及优缺点

    万次阅读 2014-11-08 17:01:01
    C#是专门为.net程序框架而创造的语言。 .net框架有ms的.netFramework, Mono的.NetFramework。 net程序编译和执行过程中的流程图: 优点: 缺点: 总结:
  • C#语言学习总结

    千次阅读 2012-09-18 19:48:09
    C#语言学习总结 对于没有任何计算机基础的人来说什么是C#语言就像你拿着捡来一片破布问程序员是什么材质一样令人费解!要想了解C#(sharp)首先让我教你点基础,  曾经有个外语系的女童鞋和我聊天时聊到这语言 她:...
  • 前言:本文给出一个从C#1.0到C#8.0的各个版本的主要C#特性 下面列出了在以前版本的 C# 语言和 Visual Studio.NET 中引入的主要功能。 1、C# 1.0 特性----第1个版本,编程语言最基础的特性,对应于Visual Studio ...
  • 自学C#语言基础

    千次阅读 2018-09-09 18:39:31
    自学C#语言基础 ** 所需要的开发工具: Vsiual studio 2015 1.C#是什么? C#是微软公司推出的一种语法简洁,类型安全的面向对象的编程语言。开发人员可以通过它编写在.NET Framework 上运行的各种安全可靠的应用...
  • C# 语言历史版本特性(C# 1.0到C# 8.0汇总) 历史版本 C#作为微软2000年以后.NET平台开发的当家语言,发展至今具有17年的历史,语言本身具有丰富的特性,微软对其更新支持也十分支持。微软将C#提交给标准组织ECMA...
  • C# 语言—基础知识

    千次阅读 热门讨论 2017-01-19 20:56:24
    前言  最近接触到了C# 语言,感觉和最初学习VB语言时的心态不一样了,现在懂得及时...1.C#语言(C sharp),是一种最新的面向对象的编程语言。它使得程序员可以快速地编写各种基于Microsoft.NET平 台的应用程序。
  • C#语言的特点

    千次阅读 2018-10-12 14:49:07
    C#语言编写的源程序--------(通过C#语言编译器)------&gt;中间语言(MicroSoft Intermediate Language,简称MSIL)代码--------- -----(通过语言运行环境CLR中的即时编译器JIT)---------&gt;CPU可...
  • 历史版本 C#作为微软2000年以后.NET平台开发的当家语言,发展至今具有17年的历史,语言本身具有丰富的特性,微软对其更新支持也十分支持。...C#语言规范GitHub库参见:https://github.com/dotnet/csharplangC#语言
  • 数据结构与算法(C#语言描述)

    千次阅读 2009-07-15 08:04:00
  • c#语言的特点

    千次阅读 2010-01-02 09:59:00
    C#在带来对应用程序的快速开发能力的同时,并没有牺牲C与C++程序员所关心的各种特性。它忠实地继承了C和C++的优点。如果你对C或C++有所了解,你会发现它是那样的熟悉。即使你是一位新手,C#也不会给你带来任何其它的...
  • C#语言打印九九乘法表

    千次阅读 多人点赞 2020-09-18 11:06:36
    C#如何打印九九乘法表 或者Java也可以哦~~ 我们都背过九九乘法表,但是用C#语音for语句循环打印出九九乘法表尝试过吗? 以下为九九乘法表打印代码 ???? using System; namespace jiujiu { class Program { ...
  • vs后期添加c#语言环境

    千次阅读 2018-01-03 10:38:22
    vs是Microsoft Visual Studio的简称,是美国微软公司的开发工具包系列产品。VS是一个基本完整的开发工具集,它包括了整个软件生命周期中所需要的大部分工具,如UML工具、代码管控工具、集成开发环境(IDE)等等。...
  • 学习c#语言真的那么容易吗?

    千次阅读 2013-11-11 13:53:03
    我工作了好几年发现学c#语言简直好深,永无止境,刚开始工作的时候简简单单的用到了几个语法,几种封装,觉得挺不错了,后来开始开发各种接口(Ucenter,腾讯微博,新浪微博,支付宝担保交易,支付宝快捷支付,易宝...
1 2 3 4 5 ... 20
收藏数 324,063
精华内容 129,625
关键字:

c#语言