可以通过using重定义类型名
using NewMsgSizeType=UInt32;
可以在命名空间A内嵌套命名空间B,相当于在A内定义一个变量B,所以A和B不能互相访问元素。
命名空间内只能包含类,枚举,结构体,委托等,不能包含变量和函数。
默认情况下存在一个全局命名空间,所以在命名空间外定义的类可以直接进入到此全局命名空间。在全局命名空间中包含的类内写static变量,就相当于全局变量。
- 基本数据类型
- 基本类型
类型 |
字节数 |
描述 |
Byte |
1 |
unsigned byte |
Sbyte |
1 |
signed byte |
Short |
2 |
signed short |
Ushort |
2 |
unsigned short |
Int |
4 |
signed integer |
Uint |
4 |
unsigned integer |
Long |
8 |
signed long |
Ulong |
8 |
unsigned long |
Float |
4 |
floating point number |
Double |
8 |
double precision number |
Decimal |
8 |
fixed precision number |
String |
Unicode string |
|
Char |
2 |
Unicode char |
Bool |
true,false,boolean |
-
- 可空类型
int? x = 5; //x可以赋值为null
与非可空类型运算时,需要显示转换
int y = (int)x* 2;或者int y = x.Value * 2;
??运算
允许给值可能为null的表达式赋另外一个值
x??y 等价x==null?y:x
使用时如:
int? x = null;
int result = x * 2 ?? 5;
结果为5
-
- Var
可以指代任何类型的变量
var x="***";
var a = new A();
class类型必须用new,在函数中传递时是引用传递(可以不用ref,但在函数中不能改变class对象的指向)。
-
- 静态成员
因为C#没有全局变量和函数。Static成员不属于对象实例,所以可以在不实例化类的情况下直接调用。
C#中,const变量也可以被static函数调用。
静态变量可以用来在类与类之间进行数据交互和共享。
class A{ public static int x=10;}
在其他任何地方,都可以使用A.x进行访问。
-
- 属性
属性比字段(变量)包含的内容多,在修改状态时还可以进行额外的操作。
包含两个函数块(get和set),一个用于获取属性,一个用于设置属性。这两个块也称为访问器。
class Data
{
int month=10;//私有的,外部不能直接访问
public int Month //指代变量
{
get { return month;}
set { month = value;}
}
}
使用时
Data data = new Data();
data.Month = 20;//设置
int x=data.Month;//获取
自动属性
public int x { set; get; }
class Cu
{
public string Name { get; set; }
public string City { get; set; }
}
Cu c = new Cu() { Name = "ab", City = "12" };
-
- 权限
只能修饰单个成员,不能用public:修饰下面的所有成员。
类可以用internal修饰,表示只能在当前项目访问。子类的可访问性不能高于父类(internal可以继承public,反之不可)。
可以用public,private,protected修饰
readonly
只能在初始化或者执行构造时赋值。仅用于修饰类的数据成员,和const不同之处在于const要求在声明时进行直接初始化,readonly是指一旦进行了写操作或者初始化,就不可以修改。
readonly修饰变量不能在函数中定义,只能修饰类的成员变量。
sealed
可以用来修饰类,该类不允许被继承。
class A
{
int x, y;
public A(int x,int y)
{ this.x = x; this.y = y;}
}
使用时:A a = new A(1, 3); //带参数的构造函数只能用new调用
A a; //该方式和无参构造无关,在类内定义无参构造没有意义,即使定义为private也可以。
父类使用virtual关键字,子类实现虚函数使用override关键字。
class B
{
public virtual void fun() {Console.WriteLine("B");}
}
class C : B
{
public override void fun(){Console.WriteLine("C");}
}
使用时:
B b=new C();
b.fun(); //输出C
和C++概念相同,父类指向子类,本质还是父类(忽略子类中除了父类以外的内容),子类只是用来改写父类的虚函数。
如果父类和子类有重名的函数或者变量,使用base在子类中引用父类的成员:base.fun();
如果没有指定继承的父类,那么就是默认只继承自System.Object。所以,每个类都是继承自System.Object。
子类中有和父类相同的成员,就会隐藏父类的成员。使用base关键字就可以访问被隐藏或者重写的父类成员,如base.fun()。
class A{A(int x){} }
class B : A {//没有protected和private继承
B():base(5){} //初始化参数列表中用base关键字指定父类构造中需要的参数
}
-
- Abstract
主要用作对象系列的基类,共享某些主要特性。
抽象类不能直接实例化,也可以和接口一样声明函数,由派生类实现。
abstract class A
{
int x;
public void fun1(){Console.WriteLine("aa");}
public abstract void fun2();
}
class B : A
{
override public void fun2(){Console.WriteLine("xx");}
}
-
- 释放对象
using(x){.......}
在using的代码块中使用变量x,代码块结束后,立即释放对象。
-
- partial
使用partial关键字可以让一个类在不同的文件中定义
============文件1内
namespace N
{
partial class A
{
public void fun1() { Console.WriteLine("fun1"); }
partial void fun3();//这种只声明,不实现的函数必须是void,而且不能用public这种修饰。如果声明的这个函数没有被实现,编译器就会在编译时自动删除相关代码。
}
}
============文件2内
namespace N
{
partial class A
{
public void fun2() { Console.WriteLine("fun2"); fun3(); }
partial void fun3() { Console.WriteLine("fun3"); }
}
}
============使用时
using N;
A a = new A();
a.fun1();
a.fun2();
- Object
可以指代任何对象
void fun(object[] obj)
{
foreach(object o in obj)
Console.WriteLine(o);
}
fun(new object[]{1,3.3,"adf"});
- 接口
interface X1{ void fun1(); void fun2();}//声明接口
interface X2 { int a { get; } }
class X : X1, X2 //用多继承接口,并实现接口
{
void X1.fun1() {Console.WriteLine("fun1");}//显示实现
public void fun2(){Console.WriteLine("fun2");}//隐式实现
public int a { get;protected set; } //实现时必须要get,set同时存在,如果接口中不存在其中一个,就要添加。添加时修饰符必须要比接口中的严格(接口是public,所以此处可以用protected)
}
调用时
X x = new X();
X1 x1 = (X1)x; //将类转换为某一接口的内容
x1.fun1();
x.fun2();
可以把函数引用保存在变量中,类似于函数指针。使用关键字delegate。
delegate void fun(int x);
void fun1(int x){}
void fun2(int x){}
//创建对象调用
fun ff = new fun(fun1);
ff(1);
//直接调用
fun ff = fun1;
ff(1);
//Lambda
fun ff = (int x) => { Console.WriteLine("{0}", x); };
ff(1);
//事件
fun ff = fun2;
ff += fun1;
ff += fun3;
ff -= fun1;
ff(1);
- Attribute
using System.Diagnostics;
添加额外信息
-
- 内置attribute
函数只在debuge下有效
[Conditional("DEBUG")]
void fun(){}
[Obsolete("过时的方法",true)] 第二个参数为编译时是否报错
void fun(){}
-
- 自定义attribute
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
//代表该Attribute只能用在class上一行,不能连续两行出现该Attribute,类在继承时不继承该Attribute
class MyAttrbute : Attribute
{
public string info;
public MyAttrbute(string msg)
{
info = msg;
}
public int vale = 0;
}
使用时:
[MyAttrbute("xxxxx", vale = 11)]
class Test{}
通过反射获取信息:
foreach (var attr in typeof(Test).GetCustomAttributes(true))
{//获取Test类的所有Attribute,找到MyAttrbute进行处理
MyAttrbute myAt = attr as MyAttrbute;
if (null != myAt)
{
Console.WriteLine(myAt.vale);
}
}
- 函数
- 引用传递
void fun(ref int x){....}
调用时(ref也是函数签名的一部分,所以调用时候也要写上。传入的参数必须有初始化[赋值]),class类型如果只是在函数中改变值,不改变指向,可以直接传递,不用ref。
int x=10;
fun(ref x);
-
- 输出参数
类似于ref,不同处在于传入的变量可以没有初始化(赋值)。在函数中,要把传入的变量作为未初始化的来处理,也就是在函数中必须要进行初始化(赋值)。
void fun(out int x){x = 10;....}
int x;
fun(out x);
-
- 不定长参数
可以声明为不确定参数个数(数组类型),该参数必须总是函数最右边的参数,且只有一个参数可以是数组类型。
下面的函数调用时可以使用:int max=fun(1,3,243,434,12);
int fun(params int[] a)
包括类,结构体,枚举(和C++完全一样),接口。
除了内存分配,类和结构与C++完全相同。
类的对象在堆中分配,使用new创建(构造函数必须加上()),当不再使用时,将自动进行垃圾清理。
结构是在栈中分配。属于轻量级快速数据类型。
-
- 结构体
结构体是值类型,而类是引用类型。
结构体没有构造函数,也不能在定义变量时赋值。
struct data
{
public int a ;
public float b;
}
data d;
d.a=10;
d.b=1.1f;
-
- 枚举
enum E{a,b,c}
E e=E.a;
if (e == E.a){.......}
enum E:uint{a=1,b=2}
int x=(int)E.a;
- 字符串
string s1 = "scca";//”scca”字面值本身就是string类型
string s2 = new string('c', 5);
char[] a = { 'a', 'b', 'c','\0'};//可以不加\0
string s3 = new string(a);
========@转译
适合地址的转换
或者string addr=”d:\1.avi”; string str=@addr;
========转换为其他类型
int x = Convert.ToInt32("12");
========其他类型转换为字符串
int x=10;
string s=x.ToString();
========转换为字符串数组
char[] a = s.ToCharArray();
========去除开头和结尾多余的空格:
s=s.Trim();
========加入字符
string s = "abc";
s=s.PadLeft(5');//可以在s前面加入两个空格,因为s原长3,要补足到5,所以加入2个
s=s.PadLeft(5,'_');//加入两个_
========分割字符串
str = str.Substring(pos,length); //从pos截取length长度(无length代表到结尾)
string s = "abc|de|fg ";
string[] str = s.Split('|');//用str.Length可以求出数组长度
foreach (string i in str)
{
Console.WriteLine(i);
}
========字符串查找
bool b=str.Contains("xxx");
- 字符串格式化
string s = string.Format("{0:D3},{1:n2}", 10, 1.23234);
//:D3表示整数至少3位,不足高位补0
//:n2表示小数点后保留2位
:c 货币形式
:x 十六进制
:000.00 用0填充不足的位数,小数点后固定两位
数组分配于堆中,是引用类型。
-
- 定义
int[] a=new int[10];
int[] a =new int[5]{ 34, 12, 32, 43, 32}
int[] a={1,2,3,4,5};
二维数组
int[,] a = new int[5, 10];//或者int[,] a={ { 3, 4 }, { 3, 2 } };
a[1,2]=5;// 赋值
-
- 遍历
数组可以用foreach循环
foreach (int x in array){...}
-
- 拷贝
将数组a的内容拷贝到数组b,数组b接收拷贝的位置是从b[2]开始
a.CopyTo(b, 2);
-
- 功能函数
int len = a.GetLength(0);//得到数组中元素个数,0代表这是一维数组
或者使用int len=a.Length;
int index = a.GetUpperBound(0);//得到数组最大下标数
-
- Linq
int[] numbers = {3,5,2,5,12,5,36,75,42};
var qur = numbers.Where((n) => n % 2 == 0).OrderBy((n) => n);
foreach (var i in qur) Console.WriteLine(i + "");
int[] ret = qur.ToArray<int>();
- 预处理
- region
当代码比较长,可以定义分组,这样就可以折叠这个区域
#region A
.................
#endregion
-
- define
#define De //在文件最开头定义一个标志
#undef De 可以进行取消定义
-
- 条件判断
如果有定义则代表会进行编译,否则会隐藏
#if De
Console.WriteLine("de");
#endif
-
- 编译消息
在文件中定义后,编译文件会弹出警告或者错误
#warning xxx
#error xxx
可以修改在编译时弹出的行号,字符串可以修改当前提示的文件名
#line 100 "flileName"
-
- Pragma
#pragma warning disable 123
#pragma warning restore 123
修饰在C#中定义的不安全的上下文,如C++的指针等。如:
public unsafe fun(int *p){ }
-
- checked
checked(….)可以检查表达式是否有溢出,如果有溢出,则程序会崩溃。
-
- lock
类似于互斥锁。
将语句块标记为临界区,方法是获取给定对象的互斥锁,执行语句,然后释放该锁,lock确保当一个线程位于代码的临界区时,另一个线程不进入临界区。如果其他线程试图进入锁定的代码,将一直等待,直到该对象被释放。
object locker = new object();
lock(locker){ ......... }
-
- case
可以用常数变量作为判断值。必须有break跳转,不支持执行完一个case执行别的case。
可以使用以下方法执行多个case
case 2:
case 3: Console.WriteLine("3"); break;
- 转换类型
- is
用于检查操作数类型是否相等或可以转换,使用两个操作数,其结果是布尔值。适合于多态的情形。
if(a is ClassA){......................}
-
- as
检查操作数的类型是否可以转换或者相等(是由is完成的),如果是,则处理结果是已转换或已装箱的对象。如果否,则返回null。
ClassA a=new ClassA();
ClassB b=a as ClassB; //返回值null,不可转换
ClassC c=a;
ClassA a2=c as ClassA; //将进行转换
-
- 重载转换
============定义
class A
{
public int val=1;
public static implicit operator B(A a) //隐式转换
{
B b = new B();
b.val = a.val;
return b;
}
}
class B
{
public long val=1000;
public static explicit operator A(B b)//显示转换
{
A a = new A();
checked { a.val = (int)b.val; }
return a;
}
}
============使用
A a = new A();
B b = a;
B b = new B();
A a = (A)b;
所有的数据类型都是从System命名空间的基类Object继承,所以基础或是原始的类型打包为一个对象,称为装箱。相反的处理称为拆箱。
int a1 = 10; object obj = a1; //装箱
int a2 = (int)obj;//拆箱
一个int值可以被转换为对象,并且能再次转换成int。
当某种值类型的变量需要被转换为一个引用类型时,便会产生一个对象箱保存该值,拆箱则完全相反。当某个对象箱被转换会其原值类型时,该值从箱中拷贝至适当的存储空间。
因为是装箱到obj,所以可以做一个List<object>,在读取的时候,通过使用is判断类型再拆箱(或使用as),实现不同类型放在同一个list中。
- 运算符重载
class A
{
public int x =10;
public static A operator+(A a1, A a2)
{
A a = new A();
a.x = a1.x + a2.x;
return a;
}
}
可以重载的运算符
一元:+,-,!,~,++,true,false
二元:+,-,*,/,%,&,|,^,<<,>>
比较:==,!=,<,>,<=,>=
重载bool运算符就可以用 if(a1){}
- 初始化器
class A
{
public string x { get; set; }
public int y { get; set; }
}
A a = new A { x="a", y=1 };//这种方法可以不使用其他构造函数或者对象来初始化成员
List<A> l=new List<A>{new A{x="a",y=1},new A{x="b",y=2}};//可以替代l.add以及赋值的语法
- 异常
public void fun()
{
throw new Exception("fun");
}
try
{
fun();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
finally
{
Console.WriteLine("try执行结束");
}
使类可以通过[]语法访问和赋值。
class Test
{
string Content1 = "aaa";
string Content2 = "bbb";
public string this[int index]
{
get
{
if(index == 1) return Content1;
if (index == 2) return Content2;
return "erro";
}
set { }
}
}
Test test = new Test();
Console.WriteLine(test[1]);
- 类型获取
string s = "";
Type t1 = s.GetType();
Type t2 = Type.GetType("system.string", false, true);
Type t3 = typeof(string);
- 反射
- 类信息
获取类中包含的可以访问的方法
Type t = typeof(Cl);
MethodInfo[] mi = t.GetMethods();
foreach (MethodInfo info in mi)
Console.WriteLine(info.Name);
//获取单个方法
MethodInfo mi = t.GetMethod("fun1");
-
- 程序集
获取程序集中包含的类
//Assembly obj = Assembly.Load("");
Assembly obj = Assembly.GetExecutingAssembly();
Type[] types = obj.GetTypes();
foreach (Type t in types) Console.WriteLine(t.Name);
- 加载使用
加载当前程序集中的Cl类,void fun1(int i,string s)函数
Assembly ass = Assembly.GetExecutingAssembly();
Type t = ass.GetType("ConsoleApplication1.Cl", false, true);
if (null == t) return;
object obj = Activator.CreateInstance(t);//创建类的实例
MethodInfo mi = t.GetMethod("fun1");
mi.Invoke(obj,new object[]{1,"a"});