1、C# csharp
Microsoft为.NET推出的高级编程语言。.NET是微软的多语言开发平台,用于构建和运行应用程序。
Mono是Novell公司支持在其他操作系统之下开发.NET程序的框架,而不是只适用于Windows。Unity借助Mono实现跨平台,核心是.NET Framework框架。
这样子Unity借助Mono实现跨平台开发。
所以Unity的核心是C#和Mono。
.Net框架的组件:
- 公共语言运行库(CLR)
- .Net框架类库
- 公共语言规范(CLS)
- 通用类型系统
- 元数据和组件
- Windows窗体(Windows Forms)
- ASP.Net 和 ASP.Net.AJAX
- ADO.Net
- Windows工作流基础
- Windows显示基础
- Windows通信基础
- LINQ
源代码–> CLS编译 --> 通用中间语言(exe dll) --> CLR编译 --> 机器码
跨语言的实现原理:CLS编译,公共语言规范,定义了.NET平台上运行的语言所必须支持的规范,用以避免不同语言特性产生的错误,实现语言间互相操作。
跨平台的实现原理:CLR编译,公共语言运行库,程序的运行环境,负责内存分配,垃圾收集,安全检查等。
2、C#代码结构
using System; // 引入命名空间
// 定义命名空间,对类进行逻辑上的划分,避免重名
// 域名.公司名.项目名
namespace Demo1
{
// 定义类,做工具
class Program
{
// 定义方法 程序的入口
static void Main(string[] args)
{
// *********程序开始执行***************
System.Console.Title = "我的第一个程序";
Console.WriteLine("Hello World!");
string hello = Console.ReadLine();
Console.WriteLine("hi :" + hello);
}
}
}
3、变量
整形:
- 1个字节:sbyte和byte
- 2个字节:short(-32768 ~ 32767)和ushort(0~65535)
- 4个字节:int和unit
- 8个字节:long和ulong
非整形: - 4字节:float, 精度7位
- 8字节:double 精度15-16位
- 16字节:128位数据类型decimal,精度28-29,适用于货币和财务计算
非数值型: - cahr:2个字节
- string字符串:存储文本
- bool类型:1个字节
4、字符串格式化
Console.WriteLine("金额:{0:c}", 10);// 货币 ¥10.00
Console.WriteLine("{0:d2}", 5); // 05
Console.WriteLine("{0:d2}", 15); //15
Console.WriteLine("{0:f1}", 1.2453);//1.2
Console.WriteLine("{0:p0}", 0.1);//10%
5 运算符
快捷运算符不做自动类型提升,+=为快捷运算符
byte a = 1;
a += 3;
// a = a + 3; 会报错
Console.WriteLine("{0}",a);
6 封装
- public:任何公有成员可以被外部的类访问
- private:只有同一个类中的函数可以访问它的私有成员。
- protected:该类内部和继承类中可以访问。
- internal: 同一个程序集的对象可以访问。
- protected internal:访问限于当前程序集或派生自包含类的类型
7 方法
按引用传递参数:
引用参数是一个对变量内存位置的引用,当按引用传递参数时,与值参数不同的是不会为这些参数创建一个新的存储位置,(值传递会创建一个临时变量)引用参数表示与提供给方法的实际参数具有相同的内存位置。
public void swap(ref int x, ref int y)
{
int temp;
temp = x; /* 保存 x 的值 */
x = y; /* 把 y 赋值给 x */
y = temp; /* 把 temp 赋值给 y */
}
8 可空类型
int? i = 3; // Nullable类型,除了为数值外,还可以为null
int i; // 默认为0
int ? ii; // 默认为null
double num1 =num ?? 5.3; // num如果为空值则返回5.34
9 数组
double[] balance = new double[10];
10 字符串
- 指定一个字符串: String fname;
- 使用String类构造函数:string str = new string(fname);
- 通过使用字符串串联运算符:message = String.Join(" ", str);
- 通过检索属性或调用一个返回字符串的方法
- 格式化方法转换一个值或对象为它的字符串表示形式:string chat = String.Format(“Message sent at {0:t} on {0:D}”,waiting);
public static int Compare(string strA, string strB);
public static int Compare(string strA, string strB, bool ignoreCase);
public static string Concat(sting str0, string str1);
11 定义结构体
结构可带有方法,字段,索引,属性,运算符方法和事件
struct Books
{
public string title;
public string author;
public string subject;
public int book_id;
}
12 枚举
enum Days {Sun, Mon, tue, Wed, thu, Fri, Sat};
13 继承
C#不支持多重继承,但是可以通过接口来实现多重继承
class Shape {}
public interface PaintCost {}
class Rectangle : Shape, PaintCost {}
14 多态性
静态继承和动态继承:
- 静态多态性:函数重载 在编译时,函数和对象的连接机制被称为早期绑定,也被称为静态绑定。
- 动态多态性:使用关键字 abstract 创建抽象类,用于提供接口的部分类的实现。当一个派生类继承自该抽象类时,实现即完成。抽象类包含抽象方法,抽象方法可被派生类实现。派生类具有更专业的功能。
sealed\virtual\abstract:
- 在类定义前面放置关键字 sealed,可以将类声明为密封类
- 用关键字 abstract 创建抽象类,用于提供接口的部分类的实现. 抽象类的要求:不能创建一个抽象类的实例,不能在一个抽象类外部声明一个抽象方法。抽象类包含抽象方法,抽象方法可被派生类实现。派生类具有更专业的功能。
- 虚方法是使用关键字 virtual 声明的。虚方法可以在不同的继承类中有不同的实现。对虚方法的调用是在运行时发生的。动态多态性是通过 抽象类 和 虚方法 实现的。
override
abstract class Shape
{
abstract public int area();
}
class Rectangle: Shape
{
private int length;
private int width;
public Rectangle( int a=0, int b=0)
{
length = a;
width = b;
}
public override int area ()
{
Console.WriteLine("Rectangle 类的面积:");
return (width * length);
}
}
virtual
public class Shape
{
public int X { get; private set; }
public int Y { get; private set; }
public int Height { get; set; }
public int Width { get; set; }
// 虚方法
public virtual void Draw()
{
Console.WriteLine("执行基类的画图任务");
}
}
15 运算符重载
通过关键字operator后跟运算符来定义
把两个box对象进行加法重载,返回box对象
public static Box operator+ (Box b, Box c)
{
Box box = new Box();
box.length = b.length + c.length;
box.breadth = b.breadth + c.breadth;
box.height = b.height + c.height;
return box;
}
public static bool operator >=(Box lhs, Box rhs)
{
bool status = false;
if (lhs.length >= rhs.length && lhs.height
>= rhs.height && lhs.breadth >= rhs.breadth)
{
status = true;
}
return status;
}
下面的运算符不能被重载:
- 条件逻辑运算符
- 赋值运算符
- =, ., ?:, ->, new, is, sizeof, typeof 不能被重载
16 接口 Interface
接口定义了“是什么”部分。包括属性,方法和事件都是接口的成员。接口只包含成员的声明,定义是用派生类实现的。
优点:使得实现接口的类或结构在形式上保持一致。
接口和抽象类的区别:
- 抽象类用在只有少数方法由基类声明由派生类实现
- 接口本身不实现任何功能。
using System;
interface IMyInterface
{
// 接口成员
void MethodToImplement();
}
class InterfaceImplementer : IMyInterface
{
static void Main()
{
InterfaceImplementer iImp = new InterfaceImplementer();
iImp.MethodToImplement();
}
public void MethodToImplement()
{
Console.WriteLine("MethodToImplement() called.");
}
}
接口继承接口
using System;
interface IParentInterface
{
void ParentInterfaceMethod();
}
interface IMyInterface : IParentInterface
{
void MethodToImplement();
}
class InterfaceImplementer : IMyInterface
{
static void main()
{
InterfaceImplementer iImp = new InterfaceImplementer();
iImp.MethodToImplement();
iImp.ParentInterfaceMethod();
}
public void MethodToImplement()
{
Console.WriteLine("MethodToImplement() called.");
}
public void ParentInterfaceMethod()
{
Console.WriteLine("ParentInteraceMethod() called.");
}
}
17 命名空间
using System;
namespace first_name
{
class namespace_c1
{
public void func()
{
Console.WriteLine("Inside first_space");
}
}
}
namespace second_name
{
class namespace_c1
{
public void func()
{
Console.WriteLine("Inside second_space");
}
}
}
class TestClass
{
static void Main(string[] args)
{
first_space.namespace_c1 fc = new first_space.namespace_c1();
second_space.namespace_c1 sc = new second_space.namespace_c1();
fc.func();
sc.func();
Console.ReadKey();
}
}
18 预处理器指令
c语言类似的:#define #undef #if #else #elif #endif
- #line
可以修改编译器的行数以及输出错误和警告的文件名
如果编写代码时,把代码发送给编译器前,要使用某些软件包改变输入的代码,就可以使用这个指令,因为这意味着编译器报告的行号或文件名与文件中得行号或编辑的文件名不匹配。
#line指令可以还原这种匹配,也可以使用语法#line default把行号还原为默认的行号。
#lien 164 "Core.cs" // 在文件的第164行
// Core.cs, before the intermediate
// package mangles it.
// later on
#line default // 恢复默认行号
- #parama
可以抑制或还原指令的编译警告,与命令行选项不同,#parama指令可以在类或方法级别执行,对抑制警告的内容和抑制的时间进行更精细的控制。
#parama warning disable 169 取消编号169的警告
public class MyClass
{
int neverUsedField;
}
#parama waring restore 169 // 恢复编号169的警告
- #region 可以在使用VS code Editor的大纲特性时,指定一个展开或折叠的代码块。
- endregion 标识着#region的结束
19 正则表达式
一种匹配输入文本的模式。
模式由一个或多个字符、运算符、结构组成。
Regex类:
- bool IsMatch(string input);
指示 Regex 构造函数中指定的正则表达式是否在指定的输入字符串中找到匹配项。
- bool IsMatch(string input, int startat);
指示 Regex 构造函数中指定的正则表达式是否在指定的输入字符串中找到匹配项,从字符串中指定的开始位置开始。
- bool IsMatch(string input, string pattern);
指示指定的正则表达式是否在指定的输入字符串中找到匹配项。
- MatchCollection Matches(string input);
在指定的输入字符串中搜索正则表达式的所有匹配项。
- string Replace(string input, string replacement);
在指定的输入字符串中,把所有匹配正则表达式模式的所有匹配的字符串替换为指定的替换字符串。
- string[] Split(string input);
根据在 Regex 构造函数中指定的正则表达式模式定义的位置进行分割。
定义正则表达式
字符转义\ 字符类\ 限定符\定位点 相关内容 请参考下一篇文章正则表达式 图文并茂 10分钟完美通关 !!!
- 反向引用构造
- 备用构造
- 替换模式
$number 替换按组 number 匹配的子字符串 \b(\w+)(\s)(\w+)\b 替换模式 $
- 杂项构造
例子:匹配以‘S’开头的单词:
using System;
using Sytem.Text.RegularExpressions;
namespace RegExApplication
{
class Program
{
pricate static void showMatch(string text, string expr)
{
Console.WriteLine("The Expressioon:" + expr)
MatchCollection mc = Regex.Matches(text, expr);
foreach(Match m in mc)
{
Console.WriteLine(m);
}
}
static void Main(string[] args)
{
string str = "A thousand splendid suns";
Console.WriteLine("Matching words that start with 'S':");
showMatch(str, @'\bS\S*');
}
}
}
19 异常处理
异常类 | 描述 |
---|---|
System.IO.IOException | 处理 I/O 错误。 |
System.IndexOutOfRangeException | 处理当方法指向超出范围的数组索引时生成的错误。 |
System.ArrayTypeMismatchException | 处理当数组类型不匹配时生成的错误。 |
System.NullReferenceException | 处理当依从一个空对象时生成的错误。 |
System.DivideByZeroException | 处理当除以零时生成的错误。 |
System.InvalidCastException | 处理在类型转换期间生成的错误。 |
System.OutOfMemoryException | 处理空闲内存不足生成的错误。 |
System.StackOverflowException | 处理栈溢出生成的错误。 |
try
{
// 引起异常的语句
}
catch( ExceptionName e1 )
{
// 错误处理代码
Throw e1;
}
catch( ExceptionName e2 )
{
// 错误处理代码
}
catch( ExceptionName eN )
{
// 错误处理代码
}
finally
{
// 要执行的语句
}
20 C#文件的输入输出
输入流用于从文件读取数据(读操作),输出流用于向文件写入数据(写操作)。
System.IO 命名空间中的 FileStream 类有助于文件的读写与关闭。该类派生自抽象类 Stream。
20.1 FileStream 类
FileStream <object_name> = new FileStream( <file_name>,
<FileMode Enumerator>, <FileAccess Enumerator>, <FileShare Enumerator>);
FileMode
- Append: 打开一个已有的文件,将光标放置文件末尾,如果文件不存在,就创建文件
- Create:创建一个新的文件,如果存在,就 删除旧文件,创建新文件
- CreateNew:创建一个新文件,如果存在,抛出异常
- Open:打开一个已有文件,如果不存在,抛出异常
- OpenOrCreate:打开一个已有文件,如果不存在,就指定的名称创建一个新的文件打开。
- Truncate:打开一个已有文件,一旦打开,就将被截断为零字节大小,然后向文件写入全新数据
FileAccess - Read
- ReadWrite
- Write
using System;
using System.IO;
namespace FileIOApplication
{
class Program
{
static void Main(string[] args)
{
FileStream F = new FileStream("test.dat",
FileMode.OpenOrCreate, FileAccess.ReadWrite);
for (int i = 1; i <= 20; i++)
{
F.WriteByte((byte)i);
}
F.Position = 0;
for (int i = 0; i <= 20; i++)
{
Console.Write(F.ReadByte() + " ");
}
F.Close();
Console.ReadKey();
}
}
}
读取中文文件在这里插入代码片
using System.Text;
System.Text.Encoding.RegisterProvider (System.Text.CodePagesEncodingProvider.Instance);
using (StreamReader sr = new StreamReader("C:/a.txt", Encoding.GetEncoding("GB2312")))
21 C# 反射
使用反射(Reflection)可以查看特性(attribute)信息
System.Reflection 类的 MemberInfo 对象需要被初始化,用于发现与类相关的特性(attribute)
System.Reflection.MemberInfo info = typeof(MyClass);
object[] attributes = info.GetCustomAttributes(true);
for (int i = 0; i < attributes.Length; i++)
{
System.Console.WriteLine(attributes[i]);
}
22 属性
访问器(Accessors):使用 访问器(accessors) 让私有域的值可被读写或操作。属性(Property)不会确定存储位置。相反,它们具有可读写或计算它们值的 访问器(accessors)。
定义抽象类
public abstract class Person
{
public abstract string Name
{
get;
set;
}
public abstract int Age
{
get;
set;
}
}
派生类:
class Student
{
private string code = "N.A";
private string name = "not known";
private int age = 0;
// 声明类型为 string 的 Code 属性
public string Code
{
get
{
return code;
}
set
{
code = value;
}
}
// 声明类型为 string 的 Name 属性
public string Name
{
get
{
return name;
}
set
{
name = value;
}
}
// 声明类型为 int 的 Age 属性
public int Age
{
get
{
return age;
}
set
{
age = value;
}
}
public override string ToString()
{
return "Code = " + Code +", Name = " + Name + ", Age = " + Age;
}
}
简化版本:
using System;
namespace Demo.cs
{
class Program
{
public abstract class Person
{
public abstract string Name { get; set; }
public abstract int Age { get; set; }
}
public class Student : Person
{
public string Code { get; set; } = "N.A";
public override string Name { get; set; } = "N.A";
public override int Age { get; set; } = 0;
public override string ToString()
{
return $"Code:{Code},Name:{Name},Age:{Age}";
}
}
static void Main(string[] args)
{
var s = new Student()
{
Code = "001",
Name = "Zara",
Age = 10
};
System.Console.WriteLine($"Student Info:={s}");
s.Age++;
System.Console.WriteLine($"Student Info:={s}");
}
}
}
23 C# 索引器
索引器(Indexer) 允许一个对象可以像数组一样使用下标的方式来访问。
为类定义一个索引器时,该类的行为就会像一个 虚拟数组(virtual array) 一样。您可以使用数组访问运算符 [ ] 来访问该类的的成员。
一维索引器的语法如下:
element-type this[int index]
{
// get 访问器
get
{
// 返回 index 指定的值
}
// set 访问器
set
{
// 设置 index 指定的值
}
}
例子:
class IndexedNames
{
private string[] namelist = new string[size];
static public int size = 10;
public IndexedNames()
{
for (int i = 0; i < size; i++)
namelist[i] = "N. A.";
}
public string this[int index]
{
get
{
string tmp;
if( index >= 0 && index <= size-1 )
{
tmp = namelist[index];
}
else
{
tmp = "";
}
return ( tmp );
}
set
{
if( index >= 0 && index <= size-1 )
{
namelist[index] = value;
}
}
}
24 C# 委托
C# 中的委托(Delegate)类似于 C 或 C++ 中函数的指针。委托(Delegate) 是存有对某个方法的引用的一种引用类型变量。引用可在运行时被改变。
委托(Delegate)特别用于实现事件和回调方法。所有的委托(Delegate)都派生自 System.Delegate 类。
实例化一个委托(Delegate)
// 声明了委托类型
public delegate void printString(string s);
...
// 委托对象必须使用 new 关键字来创建
// 与一个特定的方法有关
// 传递到 new 语句的参数就像方法调用一样书写,但是不带有参数
printString ps1 = new printString(WriteToScreen);
printString ps2 = new printString(WriteToFile);
委托的多播(实现调用列表):
委托对象可使用 “+” 运算符进行合并。一个合并委托调用它所合并的两个委托。只有相同类型的委托可被合并。"-" 运算符可用于从合并的委托中移除组件委托。
使用委托的这个有用的特点,您可以创建一个委托被调用时要调用的方法的调用列表。这被称为委托的 多播(multicasting),也叫组播。
// 定义一个委托
delegate int NumberChanger(int n);
// 创建委托实例
NumberChanger nc;
NumberChanger nc1 = new NumberChanger(AddNum);
NumberChanger nc2 = new NumberChanger(MultNum);
nc = nc1;
nc += nc2;
// 调用多播
nc(5);
25 C#事件
事件(Event) 基本上说是一个用户操作,如按键、点击、鼠标移动等等,或者是一些提示信息,如系统生成的通知。应用程序需要在事件发生时响应事件。例如,中断。
C# 中使用事件机制实现线程间的通信。
定义了一个名为 BoilerLogHandler 的委托和一个名为 BoilerEventLog 的事件,该事件在生成的时候会调用委托。
// 声明事件
public delegate void BoilerLogHandler(string status);
// 基于上面的委托定义事件
public event BoilerLogHandler BoilerEventLog;
26 C#集合
动态数组 ArrayList
哈希表 HashTable
排序列表 SortedList
堆栈 Stack
队列 Queue
点阵列 BitArray
27 C#泛型
编写一个可以与任何数据类型一起工作的类或方法。
// 泛型方法
static void Swap<T>(ref T lhs, ref T rhs)
// 泛型类
public class MyGenericArray<T>
// 泛型委托
delegate T NumberChanger<T>(T n);
泛型约束
public class CacheHelper<T> where T:new()
28 C#匿名方法
提供了一种传递代码块作为委托参数的技术。匿名方法是没有名称只有主体的方法。
delegate void NumberChanger(int n);
...
NumberChanger nc = delegate(int x)
{
Console.WriteLine("Anonymous Method: {0}", x);
};
代码块 Console.WriteLine(“Anonymous Method: {0}”, x); 是匿名方法的主体。
委托可以通过匿名方法调用,也可以通过命名方法调用,即,通过向委托对象传递方法参数。