C# 基础知识(一)

文章目录

        • 一,简介
        • 二,环境
        • 三,基本语法
          • 各种定义
          • 输入和输出
          • 类型转换
        • 四, 数据类型
          • NET
          • C# 数据类型
        • 五,运算
        • 面向对象的编程
          • 修饰符
          • 属性
        • 六,控制结构
        • 七,数组
        • 八,方法
        • 九,继承


一,简介

C# 是一个现代的、通用的、面向对象的编程语言,它是由微软(Microsoft)开发的,由 EcmaISO 核准认可的。
C# 是专为公共语言基础结构(CLI)设计的。CLI 由可执行代码和运行时环境组成,允许在不同的计算机平台和体系结构上使用各种高级语言。

C# 成为一种广泛应用的专业语言的原因有以下几点:

  • 现代的、通用的编程语言。
  • 面向对象
  • 面向组件
  • 容易学习
  • 结构化语言
  • 可以产生高效率的程序
  • 可以在多种计算机平台上编译
  • .Net 框架的一部分。

C# 强大的编程功能
虽然 C# 的构想十分接近于传统高级语言 CC++,是一门面向对象的编程语言,但是它与 Java 非常相似,有许多强大的编程功能

下面列出 C# 一些重要的功能:

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

二,环境

C# 是 .Net 框架的一部分,且用于编写 .Net 应用程序。

.Net 框架(.Net Framework)
.Net 框架是一个创新的平台,可以编写出下面类型的应用程序:

  • Windows 应用程序
  • Web 应用程序
  • Web 服务

.Net 框架应用程序是多平台的应用程序。框架的设计方式使它适用于下列各种语言:
C#、C++、Visual Basic、Jscript、COBOL 等等。
所有这些语言可以访问框架,彼此之间也可以互相交互

.Net 框架由一个巨大的代码库组成,用于 C# 等客户端语言。下面列出一些 .Net 框架的组件:

  • 公共语言运行库(Common Language Runtime - CLR)
  • .Net 框架类库(.Net Framework Class Library)
  • 公共语言规范(Common Language Specification)
  • 通用类型系统(Common Type System)
  • 元数据(Metadata)和组件(Assemblies)
  • Windows 窗体(Windows Forms)
  • ASP.Net 和 ASP.Net AJAX
  • ADO.Net
  • Windows 工作流基础(Windows Workflow Foundation - WF)
  • Windows 显示基础(Windows Presentation Foundation)
  • Windows 通信基础(Windows Communication Foundation - WCF)
  • LINQ

C# 编程的开发工具

C# 的集成开发环境(Integrated Development Environment - IDE)
微软(Microsoft)提供了下列用于 C# 编程的开发工具:

  • Visual Studio (VS) (推荐)
  • Visual C# 2010 Express (VCE)
  • Visual Web Developer

在 Linux 或 Mac OS 上编写 C# 程序

虽然 .NET 框架是运行在 Windows 操作系统上,但是也有一些运行于其它操作系统上的版本可供选择。Mono 是 .NET 框架的一个开源版本,它包含了一个 C# 编译器,且可运行于多种操作系统上,比如各种版本的 LinuxMac OS

Mono 的目的不仅仅是跨平台地运行微软 .NET 应用程序,而且也为 Linux 开发者提供了更好的开发工具。Mono 可运行在多种操作系统上,包括 Android、BSD、iOS、Linux、OS X、Windows、Solaris 和 UNIX。

三,基本语法

执行 C# 代码的过程包括下列步骤:

1.选择编译器
2.将代码编译为 MSIL
3.将MSIL编译为本机代码
4.运行代码
5.垃圾回收
注:MSIL包括用于加载,存储和初始化对象以及对对象调用方法的指令,还包括用于算术和逻辑运算,控制流,直接内存访问,异常处理和其他操作的指令。

在面向对象的编程方法中:

  • 对象是核心
  • 对象由类建模而成
  • 把类转换为对象的过程称为类的实例化
  • 对象是消息,数据和行为的组合
  • 对象代表一个实实在在存在的实体(实际物体)或者实际概念
  • 对象往往有边界,有属性,有方法(特定用途)

面向对象的程序设计思想是现代软件开发的基础

面向对象的程序由各种各样的类,对象和方法组成

一般而言,对象具有一下特性:

  • 对象有状态,对象的状态由对象的各种属性和相应值构成
  • 对象可以显示行为(即方法),对象的行为(方法)使对象可以完成相应功能
  • 对象有一个唯一的身份,对象的身份可以把它与其他对象区分开来
    (两个对象可能什么都相同,但是它们不可能有相同的身份)
各种定义

using 关键字:用于在程序中包含命名空间。一个程序可以包含多个 using 语句。在任何 C# 程序中的第一条语句都是:

using System;

class 关键字:用于声明一个

注释:用于解释代码,编译器会忽略注释的条目。在 C# 程序中,多行注释以 /* 开始,并以字符 */ 终止;单行注释是用 ‘//’ 符号表示。

C# 中 // 注释和 /// 注的区别::C# 引入了新的 XML 注释,即我们在某个函数前新起一行,输入 ///,VS.Net 会自动增加 XML 格式的注释
// 不会被编译,而 /// 会被编译
所以使用 /// 会减慢编译速度(但不会影响执行速度)
但使用 /// 会在其它的人调用你的代码时提供智能感知(通常在Form。Designer.cs 窗口会自动生成 /// 注释的程序)

成员变量:变量是类的属性或数据成员,用于存储数据

成员函数:函数是一系列执行指定任务的语句。类的成员函数是在类内声明的。

C# 类的实例化:通过已有的类(class)创建出该类的一个对象(object),这一过程就叫做类的实例化。

标识符:标识符是用来识别类、变量、函数或任何其它用户定义的项目。在 C# 中,类的命名必须遵循如下基本规则:

  • 标识符必须以字母开头,后面可以跟一系列的字母、数字( 0 - 9 )或下划线( _ )。
  • 标识符中的第一个字符不能是数字
  • 标识符必须不包含任何嵌入的空格或符号,比如 ? - +! @ # % ^ & * ( ) [ ] { } . ; : " ’ / \。但是,可以使用下划线( _ )。
  • 标识符不能是 C# 关键字

C# 关键字:关键字是 C# 编译器预定义的保留字。这些关键字不能用作标识符,但是,如果想使用这些关键字作为标识符,可以在关键字前面加上@字符作为前缀。在 C# 中,有些标识符在代码的上下文中有特殊的意义,如 get 和 set,这些被称为上下文关键字(contextual keywords)。

下表列出了 C# 中的保留关键字(Reserved Keywords)和上下文关键字(Contextual Keywords):

保留关键字列表

abstract as base bool break byte case
catch char checked class const continue decimal
default delegate do double else enum event
explicit extern false finally fixed float for
foreach goto if implicit in in (generic modifier) int
interface internal is lock long namespace new
null object operator out out(generic modifier) override params
private protected public readonly ref return sbyte
sealed short sizeof stackalloc static string struct
switch this throw true try typeof uint
ulong unchecked unsafe ushort using virtual void
volatile while

上下文关键字列表

add alias ascending descending dynamic from get
global group into join let orderby partial (type)
partial (method) remove select set

字段:属性在类的声明中用变量表示,这样的变量称为字段(field)。
字段是在类声明的内部声明的,但是位于类的方法声明体之外。当类的每个对象维护自己的属性副本时,代表属性的字段又称为实例变量。

方法(Method):描述了类实际执行任务的机制,从形式上看,相当于C语言的函数

字段和方法都具有访问权限,主要为代码的安全考虑
通常有 3 种访问权限:private(私有的), public(公共的), protected(保护的)
使用权限:

  • private 修饰的字段或者方法只允许在类的内部使用
  • public 修饰的字段或者方法则没有什么限制,从类的外部可以直接使用
  • protected 修饰的字段和方法可以在派生类中使用

命名空间:namespace中文多翻译为名字空间(或者命名空间)。
名字空间是用来组织和重用代码的编译单元,所谓namespace,是指标识符的各种可见范围。

System(名字空间).Console(类名).WriteLine(方法名)(“hello”)(要输出的函数参数);

在名字的开头使用 using 语句表示引用该名字空间,在代码书写中可以省略名字空间 。namespace 是 C# 的一个关键字,实际上,它只是起到标识作用,把需要的内容放到一起,细化管理,也可以定义自己的命名空间。
在新建C#项目时,会自动地把所有的东西放到一个新的名字空间里,这个名字空间默认的名字就是项目的名字

Main():一个项目可以就是你开发的一个软件,从扩展名来看,应用程序都会编译为一个 .exe 文件,既然是.exe文件,就表明它是可以被执行的。表现在程序中,这些应用程序都有一个主程序入口点,即Main()。
而类库,Windows控件等,则没有这个入口点,所以不能直接执行,而仅提供一些功能,给其他项目调用。这样的程序后缀名为 .dll
Visual Studio除了建立了一个控制台项目之外,该项目同时还属于一个解决方案

现在以下面这段代码为例找找这四种分别是什么:

  • 字段
  • 方法
  • 主函数
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace liti
{
    class Program
    {
        static void Main(string[] args)  //主函数
        {
            MyClass haha = new MyClass();  //创建新的类的实例
            haha.SayHello();  //执行类里面的方法
        }
    }
    class MyClass  //类,MyClass是类名,可以自己命名,需要符合标识符的规定
    {
        private int x;  //成员字段,可以存储一个数据
        //因为使用权限是private,所以不可以在主函数里不可访问x
        public void SayHello()  //成员方法,相当于c语言里的函数
        //因为使用权限是public,所以可以在主函数里可以访问SayHello
        {
            Console.WriteLine("hello world!");
        }
    }
}
输入和输出

在一行输入一个数据,求两个数的和

  • Console.Read():在一行输入一个字符
  • Console.ReadLine():在一行输入一串字符
  • Console.Write():输出时不换行
  • Console.WriteLine():输出时换行
using System;
namespace liti
{
    class Program
    {
        static void Main(string[] args) 
        {
        	//在一行输入一个数据
            //Console.Read();  //读取一个字符
            string s = Console.ReadLine();  //读取一行字符 
            int x = Convert.ToInt32(s);  //将字符串转换为整数
            s = Console.ReadLine();
            int y = Convert.ToInt32(s);  //必须手动转换
            int z = x + y;  
            //Console.Write(z);  //输出后不换行
            Console.WriteLine(z);  //输出后自动换行
            //z会自动转换为字符输出
        }
    } 
}

在一行输入多个数据,并求和

  • ss1 = s1.Split(’ '):将输入的数据根据空格分解为子串
  • Console.WriteLine(“和是{0}”, sum):带格式输出
using System;
namespace liti
{
    class Program
    {
        static void Main(string[] args) 
        {
            //在一行输入多个数据
            string s1 = Console.ReadLine();  //输入数据,中间用空格隔开
            string[] ss1 = s1.Split(' ');  //Split方法表示按括号内分隔符拆分字符串
            //s1 是一个类,类中有很多方法,比如Split方法
            double[] a = new double[ss1.Length];  //分配新的空间
            double sum = 0;
            for (int i = 0; i < ss1.Length; i++)
            {
                a[i] = Convert.ToDouble(ss1[i]);  //将字符串转换为double型
                sum = sum + a[i];  //求和
            }
            Console.WriteLine(sum);
            //带格式输出
            Console.WriteLine("和是{0}", sum);  //大括号里的数必须从0开始
        }
    } 
}

类型转换

类型转换是把数据从一种类型转换为另一种类型。在 C# 中,类型转换有两种形式:

  • 隐式类型转换 这些转换是 C# 默认的以安全方式进行的转换。例如,从小的整数类型转换为大的整数类型,从派生类转换为基类。
  • 显式类型转换 这些转换是通过用户使用预定义的函数显示完成的。显式转换需要强制转换运算符

C# 提供了下列内置的类型转换方法:

序号 方法 描述
1 ToBoolean 如果可能的话,把类型转换为布尔型。
2 ToByte 把类型转换为字节类型。
3 ToChar 如果可能的话,把类型转换为单个 Unicode 字符类型。
4 ToDateTime 把类型(整数或字符串类型)转换为日期-时间结构。
5 ToDecimal 把浮点型或整数类型转换为十进制类型。
6 ToDouble 把类型转换为双精度浮点型。
7 ToInt16 把类型转换为 16 位整数类型。
8 ToInt32 把类型转换为 32 位整数类型。
9 ToInt64 把类型转换为 64 位整数类型。
10 ToSbyte 把类型转换为有符号字节类型。
11 ToSingle 把类型转换为小浮点数类型。
12 ToString 把类型转换为字符串类型。
13 ToType 把类型转换为指定类型。
14 ToUInt16 把类型转换为 16 位无符号整数类型。
15 ToUInt32 把类型转换为 32 位无符号整数类型。
16 ToUInt64 把类型转换为 64 位无符号整数类型。

四, 数据类型

在 C# 中,变量分为以下几种类型:

  • 值类型(Value types)
  • 引用类型(Reference types)
  • 指针类型(Pointer types)

值类型

值类型变量可以直接分配给其一个。它们是从类 System.ValueType 中派生的。值类型直接包含数据。比如 int、char、float,它们分别存储数字、字母和浮点数。当声明一个 int 类型的变量时,系统将会分配内存来存储它的值。

如需得到一个类型或一个变量在特定平台上的准确大小,可以使用 sizeof 方法。表达式 sizeof(type) 产生以字节为单位存储对象或类型的存储尺寸。

引用类型
引用类型不包含存储在变量中的实际数据,但它们包含对变量的引用。
换句话说,它们指向的是一个内存位置。使用多重变量时,引用类型可以指向一个内存位置。如果内存位置的数据是由多重变量之中的一个改变的,其他变量会自动相应这种值的变化。例如,内置的引用类型有:object、dynamic 和 string。

对象类型
对象类型是 C# 通用类型系统(CTS)中所有数据类型基类。 Object 是 System.Object 类的别名。对象类型可以被分配任何其他类型(值类型、引用类型、预定义类型或用户自定义类型)的值。但是,在分配值之前,需要先进行类型转换。

当一个值类型转换为对象类型时,则被称为装箱;另一方面,当一个对象类型转换为值类型时,则被称为拆箱

object obj;
obj = 100; // 这是装箱

动态类型
可以在动态数据类型变量中存储任何类型的值。这些变量的类型检查是在运行时进行的。

声明动态类型的语法:

dynamic = value;

例如:

dynamic d = 20;

动态类型与对象类型相似,但是对象类型变量的类型检查是在编译时进行的,而动态类型变量的类型检查是在运行时进行的。

字符串类型
字符串类型允许给变量分配任何字符串值。字符串类型是 System.String 类的别名。它是从对象类型派生的。字符串类型的值可以通过两种形式进行分配:引号和 @ 引号。

指针类型
指针类型变量存储另一种类型的内存地址。C# 中的指针与 C 或 C++ 中的指针有相同的功能。

char* cptr;  //声明指针
int* iptr;

根据代码了解下列知识:

  • 变量的声明
  • 表达式
  • 值变量
  • 引用变量
       int x;  //声明变量
       int y = 90;  //声明常量
       float a, b, c;  //声明多个变量 
       float d = a + b + c;  //表达式
       bool k = a > b;  //值为真或假
       const double PI = 3.14159;  //声明符号常量
       decimal balabala = 0.0m;  
       //以上变量为值类型变量
       int[] num = new int[100];  //引用型变量
      
NET

NET中类型的两个基本类别是“值类型”和“引用类型”。

值类型:基元类型,枚举,结构
值类型包括:

  • 所有数字数据类型
  • Boolean, Char 和 Data
  • 所有结构,即使其成员是引用类型
  • 枚举,因为其基础类型总是SByte, Short, Integer, Long, Byte

引用类型:类,字符串,标准模块,接口,数组,委托
引用类型包括:

  • string
  • 所有数组,即使其元素是值类型
  • 类类型,如Form
  • 委托
  • 自描述类型
  • 指针类型
  • 接口类型
    C# 基础知识(一)_第1张图片
    根类型 System.Object, 它非常特殊,因为它既不是引用类型也不是值类型,而且不能实例化
    数据在内存中的分配位置,取决于该变量的数据类型
C# 数据类型
  • 值类型:C#数据存储,栈空间,堆空间(垃圾回收)值类型的变量,所有的数值类型等,struct 结构,直接在里分配存储,方法结束后销毁
  • 引用类型:所有的类类型,数组,string等;在里用 new 来分配空间,通过垃圾回收(GC)来管理;同时将分配的内存标识(句柄)放到栈里。

对于引用类型,两个变量可能引用同一个对象
对于值类型,每个变量都有它们自己的数据副本
C# 基础知识(一)_第2张图片
C#值类型

  • 简单类型
    C# 基础知识(一)_第3张图片
  • 枚举类型

定义:枚举类型是具有命名常量的独特的类型。每种枚举类型都具有一个基础类型,该基础类型必须是八种整数之一(如果没有声明是哪一种基础类型,默认是int类型)

枚举的声明:

访问修辞符 enum 枚举名:基础类型
{
     枚举成员
}

枚举成员是该枚举类型的命名常数
任何两个枚举成员不能具有相同的名称
简单的枚举示例:

public enum time:uint
{
	Morning = 1,
	Afternoon = 2,    //枚举成员之间用逗号隔开
	Evening = 3    //最后一个枚举成员后面没有逗号
}

如果没有给枚举成员赋值,默认为0。以后的枚举成员值由前一个枚举成员的值加1得到
System.Enum 本身不是枚举类型。它是一个类类型,所有枚举类型都是从它派生的

  • 结构类型

定义:结构是使用 struct 关键字定义的,与类相似,都表示可以包含数据成员和函数成员的数据结构。
结构是一种值类型,并且不需要堆分配(不使用 new 运算符)
结构不能声明默认构造函数或析构函数
简单的结构示例:

struct Haha
{
	public int x;    
	public int y;
	public static string str = null;    //静态变量可以初始化
	public Haha(int x, int y)    //带参数的构造函数
	{
		this.x = x;
		this.y = y;
		Console.WriteLine("x = {0}, y = {1}, str = {2}", x, y, str);
	}
}   

关于枚举和结构如何使用的例子:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace litii
{ 
    class Program
    {
        struct Haha    //结构
        {
            public int age;
            public string name;
        }
        enum DayTime    //枚举
        {
            Morning,
            Afternoon,
            Evening
        }
        static void Main(string[] args)     //主函数
        {
            Haha s1;
            s1.age = 18;
            Haha[] s2 = new Haha[100];
            DayTime d1;
            d1 = DayTime.Morning;  
        }
    }
}

C#引用类型

  • 类类型
  • 接口类型
  • 数组类型
  • 委托类型

C#类型由用户定义的类别:类类型,结构类型,接口类型,枚举类型,委托类型

引用类型的值都被当做 “ 对象 ” 来处理
值类型的值则通过执行装箱拆箱操作亦按对象处理
示例:

	int i = 123;
	object o = i;    //装箱
	int j = (int)o;    //拆箱

由于这种统一性,使用 object 类型的通用库既可以用于引用类型,又可以用于值类型

五,运算

关于后缀:

C# 基础知识(一)_第4张图片
C#提供的字符类型数据按照国际上公认的标准,采用 Unicode 字符集。一个Unicode 字符的长度为 16 位( bit ),它可以用来表示世界上大部分语言种类。所有 Unicode 字符的集合构成字符类型。字符类型的类型标识符是 char, 因此也可称为 char 类型。
在表示一个字符常数时,单引号内的有效字符数量必须且只能是一个,并且不能是单引号或则反斜杠( \ ) 。
一个字符串是被双引号包含的一系列字符。

C#支持的字符串常数:

1.常规字符串常数
2.逐字字符串常数:@ 开头的字符串
例如:@ “ 计算机 ”
逐字字符串常数同常规字符串常数的区别在于,在逐字字符串常数的双引号中,每个字符都代表其最原始的意义,在逐字字符串常数中没有转义字符

推断类型可以是内置类型,匿名类型,用户定义类型或,NET Framework 类库中定义的类型。

	var i = 10;    //隐式声明
	int i = 10;    //显示声明
	//两句功能一样,前者更加方便简介一些

表达式

概念:表达式是由运算符将运算对象(如常数,变量和函数等)连接起来的具有合法语义的式子。
注:如果除数和被除数均为整数类型,则结果也是整数。(只取整数部分)
“ % ” 运算符两侧均应为整型数据,其运算结果为两个运算对象作除法运算的余数。

位运算符:

1.按位与( & ):两个整型数据中的二进制做 “ 与 ” 运算。
“ 与 ” 运算规则为:如果参加运算的两个二进制位为 1 ,则结果为 1 ,否则结果为 0 。

2.按位或( | ):两个整形数据中的二进制位做 “ 或 ” 运算。
“ 或 ” 运算规则为:只要参加运算的两个二进制位中有一个为 1 ,则结果就是 1;只有在参加运算的两个 2 进制位均为 0 的情况下结果才是 0。

3.按位异或( ^ ):两个整型数据中的二进制位做 “ 异或 ” 运算。
“ 异或 ” 运算规则为:如果参加运算的两个二进制位不同则运算结果为 1,相同则结果为 0。

4.按位取反( ~ ):按位取反是单目运算符,只需一个运算对象,按位取反运算将作为运算对象的整型数据中的二进制位做 “ 求反 ” 运算。
“ 求反 ”运算规则:如果原来的二进制位为 1,则运算结果为 0,否则结果为 1,即运算结果和原来的数据相反。

5.左移位运算符( << ):左移位运算符用于将整型数据中的各个二进制位全部左移若干位,并在该数据的右端添加相同个数的 0。

6.右移位运算符( >> ):右移位运算符用于将整型数据中的各个二进制位全部右移若干位,并在该数据的左端添加相同个数的 0。

C# 基础知识(一)_第5张图片
C# 基础知识(一)_第6张图片
C#中的数学函数大多是 Math 类的静态方法,而 Math 类在名字空间 System 中。
例如:

	double y = Math.Cos(0.5);

C# 基础知识(一)_第7张图片

C# 基础知识(一)_第8张图片

面向对象的编程

面向对象编程( Object Oriented Programming, OOP, 面向对象程序设计)是一种计算机编程架构。

面向对象编程中的概念主要包括:
类,对象,数据抽象,数据封装,继承,动态绑定,多态性,消息传递。
最基本的特征:封装,继承,多态

通过继承可以创建:派生类,基类
派生类可以从其基类中继承属性和方法

继承的目的:代码的重用

多态性是指不同类的对象对同一消息作出不同的响应
多态的作用:实现接口重用

类是对一些具有相同数据和操作的事物的描述
在C#中,数据称为字段,操作称为方法

类的其中两个成员:

  • 字段成员,它存储与类的实例相关的数据
  • 方法成员,它是执行代码。方法成员通常模拟类所表示的现实世界事物的功能和操作。
修饰符

类修饰符:限定声明类的一种符号

  • 访问修饰符
    C# 基础知识(一)_第9张图片
  • 其他修饰符
    C# 基础知识(一)_第10张图片
    类成员可以在类主体内部以任何顺序声明。

成员修饰符:

  • 访问修饰符
    (1)私有的( private ):声明私有成员,系统缺省值是 private
    (2)公有的( public ):声明公有成员
    (3)保护的( protected ):不能被类外对象访问,可以被派生类的方法与属性引用
    (4)内部的( internal ):只能在程序集内使用
    (5)受保护内部的( protected internal )
  • 其他修饰符
    (1)abstract :指示该方法或属性没有实现
    (2)const :指定域或局部变量的值不能被改动
    (3)event :声明一个事件
    (4)extern :指示方法在外部实现
    (5)override :对由基类继承成员的新实现
    (6)readonly:指示一个域只能在声明时以及相同类的内部被赋值
    (7)static :指示类的静态成员,为全体类的对象所共有

字段初始值:
每种类型的默认值都是0;bool型时是false;引用类型默认为null。

构造方法:没有返回值,名字和类名相同,可以传递参数,可以重载
例如:

public Person()    //没有参数的构造方法
{
	Name = "lili";
	Age = 18;
	Weight = 126;
}
属性

类的属性:C#中属性体现了对象的封装性。

属性是类、结构体和接口的命名成员。类或结构体中的成员变量或方法称为。属性是域的扩展,且可使用相同的语法来访问。它们使用访问器让私有域的值可被读写或操作。

属性不会确定存储位置。相反,它们具有可读写或计算它们值的访问器。
例如,有一个名为 Student 的类,带有 age、name 和 code 的私有域。我们不能在类的范围以外直接访问这些域,但是我们可以拥有访问这些私有域的属性。
访问器

属性的访问器包含有助于获取(读取或计算)或设置(写入)属性的可执行语句。访问器声明可包含一个 get 访问器、一个 set 访问器,或者同时包含二者。

private string id = "1919";
public string ID
{
	get 
	{
		return id;
	}
	set
	{
		id = value;
	}
}
    // public string ID { get; set; }    与上面代码效果一样	

数据类型的存储方式,位置:

是一个内存数组,是一个LIFO(last-in first-out,后进先出)的数据结构。
栈存储几种类型的数据:

  • 变量的值
  • 程序当前的执行环境
  • 传递给方法的参数

是一块内存区域,在堆里可以分配大块的内存用于存储某类型的数据
所有引用类型的数据都会分配到堆里面(使用 new 分配内存)
值类型只需要一段单独的内存,用于存储实际的数据
引用类型需要两端内存:
第一段存储实际的数据,位于堆中;
第二段是一个引用,指向数据在堆中存放位置。

看下面一道例题理解下列知识:

  • 构造函数(构造方法)
  • 析构方法:不带有参数,没有重载,不能继承
  • 属性
  • 访问权限
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace litii
{ 
    class Program
    {
        
        static void Main(string[] args)   
        {
            Hero baizd = new Hero();
            baizd.AddLife();
            baizd.Life = 90;     //自动调用属性中的set过程,90这个值会传递给value
            int k = baizd.Life;    //自动调用属性中的get过程
            //属性在等号左边调用set过程,属性在等号右边调用get过程
        }
    }

    class Hero    //类
    {
        private string name;    //字段
        private  int life = 50;

        public int Life  //属性
        {
            get
            {
                return life;
            }
            set    //根据需要写不同的代码
            {
                if (value < 0)
                    life = 0;
                else
                {
                    if (value > 100)
                        life = 100;
                    else
                        life = value;
                }
            }
        }

        public string Name     //属性
        {
            get
            {
                return name;
            }
            set   
            {
                name = value;
            }
        }
        public int Age { get; set; }   //如果不需要做任何处理,可以这样写(可不写)
        //效果和 Name 属性一样

        public void AddLife()    //方法
        {
            life++;
        }

        public Hero()    //构造方法,在创建实例的时候自动被调用,且只被调用一次
        {
            life = 0;    //如果一个类没有写构造方法,系统会自动添加一个构造方法
            name = " ";     //不需要写返回值
        }

        ~Hero()    //默认权限为private
        {
               //析构方法,销毁构造方法
        }
    }
}

六,控制结构

  • 选择结构

例题:输入三个数判断这三个数是否可以构成三角形

using System;
namespace litii
{ 
    class Program
    {  
        static void Main(string[] args)   
        {
            double a, b, c;
            //string s = Console.ReadLine();
            var s = Console.ReadLine();
            var ss = s.Split(' ');
            a = Convert.ToDouble(ss[0]);
            b = Convert.ToDouble(ss[1]);
            c = Convert.ToDouble(ss[2]);
            if (a + b > c && b + c > a && a + c > b) 
            {
                Console.WriteLine("YES");
            }
            else
            {
                Console.WriteLine("NO");    
            }
        }
    }
}
  • 循环结构
    例题:输入a(1~9),求 a + aa + aaa + aaaa + aaaaa + aaaaaaa 的值
using System;
namespace litii
{ 
    class Program
    {
        
        static void Main(string[] args)   
        {
            int a;
            var s = Console.ReadLine();
            a = Convert.ToInt32(s);
            int sum = 0;
            int aNext = a;

            //int n = 0;
            //while (n < 7)
            //{
            //    sum = sum + aNext;
            //    aNext = aNext * 10 + a;
            //    n++;
            //}

            //int n = 0;
            //do
            //{
            //    sum = sum + aNext;
            //    aNext = aNext * 10 + a;
            //    n++;
            //} while (n < 7);

            for (int i = 1; i <= 7; i++)
            {
                sum = sum + aNext;
                aNext = aNext * 10 + a;
            }

            Console.WriteLine("Sum={0}", sum);
        }
    }
}
  • 其他控制语句:switch,break,continue
using System;
namespace litii
{ 
    class Program
    {
        static void Main(string[] args)   
        {
            var s = Console.ReadLine();
            int garde = Convert.ToInt32(s);
            int f;
            switch (garde / 10)
            {
                case 10:    //什么都没有可以不加break
                case 9:
                    f = 5;
                    break;
                case 8:
                    f = 4;
                    break;
                case 7:
                    f = 3;
                    break;
                default:
                    f = 1;
                    break;
            }
            Console.WriteLine("f={0}", f);
            for (int i = 0; i < 3; i++)
            {
                if (f == 1)
                {
                    continue;
                }
                else
                {
                    Console.WriteLine("nice!");
                }
            }
        }
    }
}

七,数组

一维数组

  • 数组中的变量又称为数组元素,变量的下标又称为索引号位置序号
  • 数组是类中的引用类型,它继承 .NET 类库中名为 System.Array 的公共基类,这样可直接使用该基类中定义的各种属性和方法

声明和创建一维数组

    int[] arr = new int [5];
    //数组类型[] 数组名 = new 数组类型[数组长度]
    int[] arr1 = new int[5]{1,2,3,4,5};    //初始化
    // int[] arr1 = new int[]{1,2,3,4,5};     //简略的写法
    // int[] arr1 = {1,2,3,4,5};     //简略的写法
    //初始值的个数要和数组长度一致
    //数组的长度可以是变量

多维数组

  • C#支持多维数组(二维及以上维数,最高32维)
  • 数组类型的维数也称为数组类型的秩,它是数组类型的方括号之间逗号个数加上1
	//二维数组
	int[,] arr = new int[2,3];    //声明
	int[,] arr = new int[2,3]{{1, 2, 3},{4, 5, 6}};    //初始化
	int[,] arr = new int[,]{{1, 2, 3},{4, 5, 6}};     //简略的写法
	int[,] arr = new {{1, 2, 3},{4, 5, 6}};    //大括号里的大括号不可以省略
	//数组类型[,] 数组名 = new 数组类型[m, n];
	//m, n可以是变量或常量表达式

交错数组

  • 交错数组是元素为数组的数组
  • 交错数组元素的长度可以不同
  • 利用交错数组可以更有效地使用内存空间
	//二维交错数组
	int[][] jagarr = new int[3][];    //交错数组的声明,第二个[]中不用写数值
	jagarr[0] = new int[5];
	jagarr[1] = new int[4];
	jagarr[2] = new int[2];
	//初始化
	jagarr[0] = new int[]{1, 2, 3, 4, 5};
	jagarr[1] = new int[]{11, 22, 33, 44,};
	jagarr[2] = new int[]{123, 456};

例题:随机填充一维数组,并在数组中顺序查找
产生 100 个 1~99 之间的随机整数,填充数组
输入一个 1~99 之间的数,如果该数字在数组中,则输出该数字在数组中的下标,
如果不在,输出-1,如果有多个,仅输出第一个匹配的下标

using System;
namespace lii
{
    class Program
    {
        static void Main(string[] args)
        {
            int[] a = new int[100];
            Random r = new Random();
            for (int i = 0; i < a.Length; i++) 
            {
                a[i] = r.Next(1, 100);  
                //括号里为产生随机数的上限和下限,下限可取,上限不可取
            }
            foreach(int k in a)  //输出
            {
                Console.Write("{0} ", k);
            }  
            int m = Convert.ToInt32(Console.ReadLine());
            for (int i = 0; i < a.Length; i++)
            {
                if (m == a[i])
                {
                    Console.WriteLine("m的位置{0}",i);
                    return;
                }
            }
            Console.WriteLine("-1"); 
        }
    }
}

利用交错数组生成杨辉三角

using System;

namespace lii
{
    class Program
    {
        static void Main(string[] args)
        {
            const int N = 10;
            int[][] pas = new int[N][];  //定义交错数组
            for(int i = 0; i < N; i++)
                pas[i] = new int[i + 1];    //为交错数组分配空间

            pas[0][0] = 1;
            for(int i = 1; i < N; i++)
            {
                pas[i][0] = 1;
                pas[i][i] = 1;
                for(int j = 1; j < i; j++)
                    pas[i][j] = pas[i - 1][j - 1] + pas[i - 1][j];
            }
            for(int i = 0; i < N; i++)
            {
                for(int j = 0; j <= i; j++)
                {
                    Console.Write("{0,-4}",pas[i][j]);
                }
                Console.WriteLine();
            }
        }
    }
}

八,方法

静态方法和静态变量

  • static 修饰符声明的成员称为静态成员
  • 使用 static 声明的成员(域,字段)变量称为静态变量
  • static 声明的方法称为静态方法
  • 静态成员是属于类所有,不需要预先创建类的实例就能访问
  • 静态成员的访问形式为:类名.静态成员,而不是“对象名.静态成员”。
  • 即静态成员是直接从类级访问,而不是从实例级访问
  • 类的所有对象共享静态变量
  • 类的静态变量仅占有一块内存空间,且该空间是不能被撤销
  • 在静态方法中只允许访问类的静态成员,而不允许访问其实例成员(即非静态成员)
  • 在实例方法中(即非静态方法)中,可以访问类中的任何成员(包括静态和非静态成员)

方法的声明:
方法在类或结构中声明,声明时需要指定访问级别(即访问修饰符),返回值,方法名,方法参数以及方法体。

方法的使用:
有返回值,方法调用仅作为表达式的形式出现

using System;

namespace lii
{
    class Program
    {
        static void Main(string[] args)  //静态方法
        {
            sun s = new sun();
            sun s1 = new sun();
            //s.sm();   //error
            sun.sm();   //"."之前是类名,不是实例名
            Console.WriteLine(sun.count++);  //参数必须是静态的
        }
    }
    class sun
    {
        public static int count = 0;
        public int a = 0;
        public static void sm()
        {
            Console.WriteLine("haha");
        }
        public sun()
        {
            count++;
        }
    }
}

方法的参数传递:

  • 值传递
  • 不使用任何修饰符标记的参数。值参数采用值方式传递(简称值传递或默认传递)。
  • 值方式传递是指在进行方法调用时,系统将实参的值复制给形参变量(即形参是实参值的一个副本),这时,方法中可使用或修改形参变量的值,但不会影响或改变实参的值。
using System;

namespace titi
{
    class Program
    {
        static void Main(string[] args)
        {
            int a = 10;
            int b = 99;
            Swap(a, b);
            Console.WriteLine("a={0},b={1}", a, b);  //输出的 a = 10, b = 99
            Swap2(ref a, ref b);
            Console.WriteLine("a={0},b={1}",a, b); //输出 a = 99, b = 10
        }

        static void Swap(int a,int b)    //值参数进行值传递
        {
            int t = a;
            a = b;
            b = t;
            Console.WriteLine("a={0},b={1}", a, b);   //输出的 a = 99, b = 10
        }

        static void Swap2(ref int a, ref int b)   //值参数进行引用传递
        {
            int t = a;
            a = b;
            b = t;
            Console.WriteLine("a={0},b={1}", a, b); //输出的 a = 99, b = 10
        }
    }
}

  • 引用参数采用引用传递。
  • 引用传递是指实参传递给形参时,不是将实参变量的值复制给形参,而是将实参的引用(即实参变量的地址)复制给形参。
  • 形参作为实参的别名与实参共享同一内存单元。因此方法中使用形参就如同使用实参一样,形参的值变了,实参值也就变了。
  • 使用 ref 修饰符标记的参数(声明和调用时都要标记)
using System;

namespace titi
{
    class Program
    {
        static void Main(string[] args)
        {
            int[] a = { 1, 2, 3 };
            AddOne(a);
            foreach (int k in a)
                Console.WriteLine(k);   // 输出为 1 2 3
            AddOne2(ref a);
            foreach (int k in a)
                Console.WriteLine(k);   // 输出为 12 13 14 15
        }

        static void AddOne(int[] a)    //引用参数进行值传递
        {
            a = new int[4] { 11, 12, 13, 14 };  //如果不加该语句输出为 2 3 4
            for (int i = 0; i < a.Length; i++)
            {
                a[i]++;
            }
        }

        static void AddOne2(ref int[] a)   //引用参数进行引用传递
        {
            a = new int[4] { 11, 12, 13, 14 };  //如果不加该语句输出为 3 4 5
            for (int i = 0; i < a.Length; i++)
            {
                a[i]++;
            }
        }
    }
}

out参数
输出(OUT参数)
使用一个方法,返回 2 个整数的和以及差

using System;

namespace titi
{
    class Program
    {
        static void Main(string[] args)
        {
            int x1 = 7;
            int x2 = 11;
            int x3;
            int x4;
            AddM(x1, x2 ,out x3, out x4);  //用out函数不用给变量赋初值
            Console.WriteLine("{0},{1}", x3, x4);
        }
        static void AddM(int x1, int x2, out int x3, out int x4)
        {
            x3 = x1 + x2;
            x4 = x1 - x2;
        }
    }
}

可选参数和命名参数

using System;

namespace titi
{
    class Program
    {
        static void Main(string[] args)
        {
            int a = 7;
            int b = 10;
            char c = 'Y';
            Sun(a, b, c);
            Sun(a,b);   //正确
            Sun(a, 1, c);
            Sun(a, c: c);  //命名参数
        }
        static void Sun(int a, int b = 1, char c = 'R') // b,c为可选参数
        {
            a = a + 1;
            Console.WriteLine("{0},{1},{2}", a, b, c);
        }  
    }
}

运行结果

8,10,Y
8,10,R
8,1,Y
8,1,Y

变长参数表
使用变长参数,求若干个整数的平均值

using System;

namespace titi
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine(Average(1));
            Console.WriteLine(Average(1, 2, 3, 4));
        }
        static double Average(params int[] a)  //变长参数表
        {
            int b = a.GetLength(0);
            double s = 0;
            foreach (int k in a)
                s += k;
            return s / b;
        }       
    }
}

方法的重载

  • 重载(Overload)
  • 方法参数数目不同
  • 方法拥有相同数目的参数,但参数的类型不一样
  • 方法拥有相同数目的参数和参数类型,但是参数类型出现的先后顺序不一样
  • 构成重载的方法与方法的返回值类型无关
using System;

namespace titi
{
    class Program
    {
        static void Main(string[] args)
        {
            double area = Area(3d, 4d, 5d);
            double area1 = Area(3, 4, 5);
        }
        static double Area(double a,double b,double c)
        {
            Console.WriteLine("1");
            double s = (a + b + c) / 2;
            return Math.Sqrt(s * (s - a) * (s - b) * (s - c));
        }
        static double Area(double a,double h)
        {
            Console.WriteLine("2");
            return (a * h) / 2;
        }
        static double Area(int a, int b,double theta)
        {
            Console.WriteLine("3");
            return (a * b * Math.Sin(theta)) / 2;
        }
    }
}

readonly:如果类中变量的值在构造函数中进行初始化,初始化后就不能修改,但不同的对象调用构造函数时可以将该变量初始化为不同的值,这样变量可以使用readonly关键字进行修饰,只读变量

九,继承

面向对象程序设计中最重要的一个概念就是继承(inheritance)。继承允许我们在另一个类中定义一个新的类,这使得它更容易创建和维护一个应用程序。这也提供了一个机会来重用代码的功能,加快实现时间。

创建一个类的时候,不是要写全新的数据成员和成员函数,程序员可以指定新的类继承一个已经存在的类的成员。已有的类称为基类(base class),新的类称为派生类(derived class)。

基类和派生类

派生类只能有一个直接基类,但一个基类可以有多个直接派生类。继承是可以传递的。定义要从其他类派生的类时,派生类会隐式获得基类的所有成员(除了其构造函数和终结器)。派生类因而可以重用基类中的代码,而无需重新实现。在派生类中,可以添加更多成员。通过这种方法,派生类可扩展基类的功能。

复数类

using System;

namespace titi
{
    class Program
    {
        static void Main(string[] args)
        {
            Complex x1 = new Complex(2, 3);
            Complex x2 = new Complex(5.6, 7.8);
            Complex x3 = x1.ADD(x2);
            x3.Show();
            Complex x4 = Complex.Add(x1, x2);
            x4.Show();
        }        
    }
    public class Complex
    {
        private double real;
        private double image;
        public Complex()
        {
            real = image = 0;
        }
        public Complex (double real,double image)
        {
            this.real = real;
            this.image = image;
        }
        public void Set(double real,double image)
        {
            this.real = real;
            this.image = image;
        }
        public double GetReal()
        {
            return real;
        }
        public double GetImage()
        {
            return image;
        }
        public Complex ADD(Complex x)
        {
            Complex temp = new Complex();
            temp.real = this.real + x.real;
            temp.image = this.image + x.image;
            return temp;
        }
        public static Complex Add(Complex x1,Complex x2)
        {
            Complex temp = new Complex();
            temp.real = x1.real + x2.real;
            temp.image = x1.image + x2.image;
            return temp;
        }
        public Complex Sub(Complex x)
        {
            Complex temp = new Complex();
            temp.real = this.real - x.real;
            temp.image = this.image - x.image;
            return temp;
        }
        public void Show()
        {
            Console.Write("{0}+{1}i", real, image);
        }
    }
}

你可能感兴趣的:(C# 基础知识(一))