【无标题】

 泛型 :
    允许我们延迟编写类或方法中的数据类型, 直到真正使用时确定类型的一种规范
    1.可以创建自己的泛型接口、泛型类、泛型方法、泛型集合 ,泛型事件和泛型委托
    2.泛型的格式:    结构<泛型的名称T> 在定义泛型时T通常用作变量类型名称。但实际上 T 可以用任何有效名称代替   
    3.泛型方法在定义是提供泛型的类型  在调用方法时 提供具体的延迟编写的类型  
    4.泛型无法直接使用运算符 比如 + -  <  > 等 但是能使用Object中的属性和方法

 
public static void Test<T>(T a, T b)

{

string temp = a.ToString();

string temp1 = b.ToString();

Console.WriteLine(temp1+temp);

}



public static void Test1<T,鸡>(T a, T b,鸡 c)

{

string temp = a.ToString();

string temp1 = b.ToString();

Console.WriteLine(c.GetType().ToString());

Console.WriteLine(temp1 + temp);

}

  1. 泛型类

C# 语言中泛型类的定义与泛型方法类似,是在泛型类的名称后面加上<T>,当然,也可以定

义多个类型,即“<T1,T2,・・・>”。

 
class People<T, C> {


private T _age;

public T Age { get; set; }

public T Eat(C a ,C b) {



return _age;

}


}

泛型接口
 
interface Inter<T>

{

void show(T t);

}


//定义接口Inter的子类InterImpA,明确泛型类型为String (2)

public class InterImpA : Inter<int>

{

//子类InterImpA重写方法show,指明参数类型为string

public void show(int t)

{

Console.WriteLine(t);

}

}

//定义接口Inter的子类InterImpB,直接声明 (1)

public class InterImpB<T> : Inter<T>

{

public void show(T t)

{

Console.WriteLine(t);

}

}

 c#内置了    IComparable 接口用于在要比较的对象的类中实现,可以比较任意两个对象。

 
  1. public class Student : IComparable<Student> {

  2. int Age { get; set; }

  3. //定义比较方法,按照学生的年龄比较

  4. public int CompareTo(Student other) {

  5. if (this.Age == other.Age)

  6. {

  7. return 1;

  8. }

  9. else if (this.Age < other.Age)

  10. {

  11. return 2;

  12. }

  13. else {

  14. return 3;

  15. }

  16. }

  17. }

2.泛型可以提供代码性能,避免了装箱和拆箱

泛型和Object类型的区别


值类型转换成引用类型。这个转换称为装箱。相反的过程称为拆箱


int number = 10;

// 装箱

object obj = number;

// 拆箱

number = (int) obj;



C# 中 Object 是一切类型的基类,可以用来表示所有类型


Object 类型


> 优点:

> 1. object类型可以用来引用任何类型的实例;

> 2. object类型可以存储任何类型的值;

> 3. 可以定义object类型的参数;

> 4. 可以把object作为返回类型。


> 缺点:

> 1. 会因为程序员没有记住使用的类型而出错,造成类型不兼容;

> 2. 值类型和引用类型的互化即装箱拆箱使系统性能下降




装箱(从值类型转换到引用类型)需要经历如下几个步骤:

int a =10

object ob = a;


首先在堆上分配内存。这些内存主要用于存储值类型的数据。

接着发生一次内存拷贝动作,将当前存储位置的值类型数据拷贝到堆上分配好的位置。

最后返回对堆上的新存储位置的引用。


拆箱(从引用类型转换为值类型)的步骤则相反:

// 拆箱

number = (int) obj;

首先检查已装箱的值的类型兼容目标类型。

接着发生一次内存拷贝动作,将堆中存储的值拷贝到栈上的值类型实例中。

最后返回这个新的值。



频繁拆装箱导致性能问题

由于拆箱和装箱都会涉及到一次内存拷贝动作,因此频繁地进行拆装箱会大幅影响性能



泛型和装箱拆箱 对比

public void abTest(object a, object b) {


Console.WriteLine(a.ToString());

Console.WriteLine(b.ToString());

}

public void abTest(T a, T b)

{


Console.WriteLine(a.ToString());

Console.WriteLine(b.ToString());

}

3. 泛型中的数据约束可以指定泛型类型的范围

泛型约束总共有五种。

约束 说明

T:结构 类型参数必须是值类型

T:类 类型参数必须是引用类型;这一点也适用于任何类、接口、委托或数组类型。

T:new() 类型参数必须具有无参数的公共构造函数。 当与其他约束一起使用时,new() 约束必须最后指定。

T:<基类名> 类型参数必须是指定的基类或派生自指定的基类。

T:<接口名称> 类型参数必须是指定的接口或实现指定的接口。 可以指定多个接口约束。 约束接口也可以是泛型的。


where T : struct //约束 T 必须是值类型

where K : class //约束 K 必须是引用类型

where V : IFace<T> //约束 V 必须实现 IFace 接口

where W : K //约束 W 必须是 K 类型,或者是 K 类型的子类

where X : class, new() //约束 X 必须是引用类型,并且有一个无参数的构造函数,当有多个约束时,new()必须写在最后

where Y : MyClass2 //约束 Y 必须是 MyClass2 类型,或者继承于 MyClass2 类





//例子:

internal class Program

{

static void Main(string[] args)

{


Person<int,string,IFaceClass,string> zhangsan = new Person<int,string,IFaceClass,string>();


zhangsan.Age = 10;

Person<float,Program,IFaceClass,Program> zhangsan1 = new Person<float,Program,IFaceClass,Program>();

zhangsan1.Age = 10.0f;


Person<double, People, IFaceClass, Man> zhangsan2 = new Person<double, People, IFaceClass, Man>();

zhangsan1.Age = 10.0f;

}

}


public class People:IComparable<People>{


public int CompareTo(People other) {


return 1;


}

}

public class Man : People {




}


public interface IFace<T> {


void IFaceMothod();



}

public class IFaceClass:IFace<int> ,IFace<float>,IFace<double>{


public void IFaceMothod() {



}

}

public class Person <T,K,V,W>

where T : struct

where K : class

where V : IFace<T>

where W : K

{


private T _age;


public T Age { get { return _age; } set { _age = value; } }



public K TesT { get; set; }


}





委托约束

枚举约束 后续再说

4.泛型成员因类型不确定,可能是类、结构体、字符、枚举……所以不能使用算术运算符、比较运算符等进行运算!
注意,可以使用赋值运算符。

5.泛型默认值问题 需要用   default()方法


之所以会用到default关键字,是因为需要在不知道类型参数为值类型还是引用类型的情况下,为对象实例赋初值。


引用类型会返回 null,对于数值类型会返回零。对于结构,此关键字将返回初始化为零或 null 的每个结构成员,具体取决于这些结构是值类型还是引用类型。对于可以为 null 的值类型,默认返回 System.Nullable<T>




///如果我们用int型来绑定泛型参数,那么T就是int型,

///那么注释的那一行就变成了 int t = null;显然这是无意义的。

///为了解决这一问题,引入了default关键字:


TestDefault<int?> testDefault = new TestDefault<int?>();

Console.WriteLine(testDefault.foo());


class TestDefault<T>

{

public T foo()

{

// T t = null; //错误赋值方式

T t = default(T);

return t;

}

}

在C#中ArrayList与List是常用的集合
ArrayList

ArrayList的优点:

    ArrayList大小是按照其中存储的数据来动态扩充与收缩的  长度不固定

    ArrayList可以很方便地进行数据的添加插入删除

   ArrayList 可以存储任意类型

ArrayList aList = new ArrayList();

//插入

aList.Add(123);

aList.Add("ABC");

aList.Insert(1, 123 + "ABC"); //123 + "ABC" ->(隐式转换)"123ABC"

//移除

aList.RemoveAt(0); //索引处

aList.Remove("ABC");

ArrayList的缺点:

    ArrayList在存储数据时使用object类型进行存储的

    ArrayList不是类型安全的,使用时很可能出现类型不匹配的错误
    就算都插入了同一类型的数据,使用时我们也需要将它们转化为对应的原类型来处理

    ArrayList 存储在装箱和拆箱操作,导致其性能低下

 
//装箱

int i = 123;

object o = i;


//拆箱

object o1 = 123;

int i1 = (int)o1; //强制类型装换

List  泛型集合

   List 与其他数组的比较:
             List与静态数组(Array类)比较类似,都用于存放一组相同类型的值。
             List与动态数组(ArrayList)比较类似   都是元素长度不固定 。

       //创建字符串类型List的对象listStr
            List<string> listStr = new List<string>();
            //创建元素位置且添加元素
            listStr.Add("a");
            Console.WriteLine(listStr[0]);
            
            //修改对应位置的元素
            listStr[0] = "b";
            for (int i = 1; i <=10; i++)
            {
                listStr.Add(i.ToString());
            }
            //添加元素
             listStr.AddRange(listStr);
            foreach (var item in listStr)
            {
                Console.WriteLine(item);
            }
            listStr.Insert(0, "a");
            listStr.IndexOf("a");
            listStr.Remove("a");
            listStr.RemoveAt(0);
            listStr.RemoveAll(x => x == "a");
            listStr.FindAll(x => x == "a");

C#中的Dictionary字典类

特点:

    必须包含名空间System.Collection.Generic
    Dictionary里面的每一个元素都是一个键值对(由二个元素组成:键和值)
    键必须是唯一的,而值不需要唯一的

    字典 长度是不固定的 随着元素增减 而改变
    键和值都可以是任何类型(比如:string, int, 自定义类型,等等)
   

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;


namespace ConsoleApp33

{

internal class Program

{

static void Main(string[] args)

{

//字典的对象

Dictionary<string,int> dic = new Dictionary<string,int>();





Dictionary<int,string> dic1 = new Dictionary<int,string>();

//添加元素

dic1.Add(0, "a");

dic1.Add(1, "b");

dic1.Add(2, "c");



dic.Add("1", 123);

dic.Add("2", 333);

dic.Add("abc", 333);

dic.Add("3", 456);

//查找

Console.WriteLine(dic1[0]);

Console.WriteLine(dic["3"]);

//修改

dic1[2] ="d";

dic["2"] = 444;


for (int i = 0; i < dic1.Count; i++)

{


Console.WriteLine(dic1[i]);


}




//dic.Keys 集合

foreach (string item in dic.Keys)

{

Console.WriteLine(dic[item]);

}



// dic.Values 集合

foreach (int item in dic.Values)

{

Console.WriteLine(item);

}


//

foreach (KeyValuePair<string,int> item in dic)

{

Console.WriteLine(item.Key);

Console.WriteLine(item.Value);

}

移除元素

bool isRmove = dic.Remove("aaadsasdasd");

if (isRmove)

{


Console.WriteLine("删除成功");

}

else {

Console.WriteLine("删除失败");


}



// //判断字典中是否包含某个key

bool isTrue = dic.ContainsKey("2");

if (isTrue)

{


dic.Remove("2");

}

else {

dic.Add("2",11);


}


// //清空

dic.Clear();

// //字典中key/value的个数

Console.WriteLine(dic.Count);



Console.ReadKey();

}

}

}

常用属性

    名称    说明
    Comparer     获取用于确定字典中的键是否相等的 IEqualityComparer<T>。
    Count        获取包含在 Dictionary<TKey, TValue> 中的键/值对的数目。
    Item         获取或设置与指定的键相关联的值。
    Keys         获取包含 Dictionary<TKey, TValue> 中的键的集合。
    Values       获取包含 Dictionary<TKey, TValue> 中的值的集合。

常用方法
    名称    说明
    Add                     将指定的键和值添加到字典中。
    Clear                    从 Dictionary<TKey, TValue> 中移除所有的键和值。
    ContainsKey         确定 Dictionary<TKey, TValue> 是否包含指定的键。
    ContainsValue       确定 Dictionary<TKey, TValue> 是否包含特定值。

    Remove              从 Dictionary<TKey, TValue> 中移除所指定的键的值。
    ToString            返回表示当前对象的字符串。 (继承自 Object。)

C# 结构体(Struct)

1.结构体是值类型数据结构。

2.引用类型派生自 System.Object ,而值类型均隐式派生自 System.ValueType

// 数值类型

Console.WriteLine(1 is ValueType); // true

// 布尔类型

Console.WriteLine(true is ValueType); // true

// 结构类型

Console.WriteLine(new Person() is ValueType); // true

// 枚举类型

Console.WriteLine(EnumTest.Item1 is ValueType); // true

3.struct 关键字用于创建结构体

 
struct MyStruct2 {


}


3.结构可带有方法、字段、属性、运算符,委托和事件。

struct MyStruct2 {

private int A;

public int Age { get; set; }

public void Test() { };

delegate void Delegate1();

event Delegate1 Delegate2;


    public static MyStruct2 operator -(MyStruct2 stu1, MyStruct2 stu2)

    {


    return new MyStruct2();


    }


}

4.结构可定义构造函数,但不能定义析构函数。不能定义无参构造函数。无参构造函数(默认)自带

如果定义有参构造函数 必须在 构造函数内部 初始化所有 字段和属性

5.结构可实现一个或多个接口  但是不能继承其他类
struct MyStruct2 {

private int A;

public int Age { get; set; }

public void Test() { };

public delegate void Delegate1();

public event Delegate1 Delegate2;


public MyStruct2(int a,int age,Delegate1 delegate1) {


A = a;

Age = age;

Delegate2 = delegate1;

}

//~MyStruct() { //错误



//}


}

6.结构不支持被其他类继承。

6.结构成员不能指定为virtual 或 protected、

7.结构可以使用 New 创建对象 也可以不使用 ,如果结构中有属性 必须使用new 创建对象

10.结构可以嵌套在类中使用 也可以和类并列定义在命名空间中

类和结构总结:

         1. 类和结构实际上都是创建对象的模板, 每个对象都包含数据,并提供了处理和访问数据的方法
           2. 类是引用类型 对象存于堆中 可以通过GC管理内存   结构是值类型 对象存于栈中  、
           3  结构不能被继承  也不能继承其他类  但是能继承接口
           4. 结构和类 都能使用new 创建对象   但是结构也可以不使用
           5. 结构作为方法参数 默认是值传递   类类型默认是引用传递

枚举

作用:

枚举是描述一组整数值的结构  使数字更具有具体意义

1.枚举是值类型

2.枚举类型使用 enum 关键字声明的。

3.枚举是一组整型常量 默认是从 0开始  也可以自己定义范围

4.枚举使用enum关键字来声明,与类同级。枚举本身可以有修饰符,但枚举的成员始终是公共的,不能有访问修饰符。枚举本身的修饰符仅能使用public和internal。

5.枚举都是隐式密封的,不允许作为基类派生子类

  enum TestEnum {
        
        A =10, B, C=100, D, E, F
   
    }

委托和事件

委托

1.委托就是把方法(函数)变成一种引用类型的方式

2.委托 关键字 delegate(代理)

3.委托分为定义委托和使用委托

  定义委托

1.定义委托和定义类一样可在命名空间中定义,也可以像变量一样在类的内部定义,

3.委托可以使用修饰符:public,private,protected等。

3.委托可以根据不同类型的方法(有参无参 有返回值 无返回值等)定义 多个委托类型

 
  1. delegate void IntMethod(int x);

  2. //定义了一个 无返回值有一个int类型参数的 委托

使用委托

//1. 创建委托类型的对象 用来管理某个符合类型的方法  并且使用委托对象 来调用方法

 
  1. delegate void VoidDelegate();

  2. delegate void VoidDelegate_1(int a);

  3. delegate void VoidDelegate_2(int a ,int b);

  4. internal class Program

  5. {

  6. static void Main(string[] args)

  7. {

  8. VoidDelegate voidDelegate = new VoidDelegate(ProgramMothod);\

  9. voidDelegate();

  10. VoidDelegate_1 voidDelegate_1 = new VoidDelegate_1(ProgramMothod_1);

  11. voidDelegate_1(10);

  12. VoidDelegate_2 voidDelegate_2 = new VoidDelegate_2(ProgramMothod_2);

  13. voidDelegate_2(10, 20);

  14. Console.ReadKey();

  15. }

  16. public static void ProgramMothod() {

  17. Console.WriteLine("1");

  18. }

  19. public static void ProgramMothod_1(int a) {

  20. Console.WriteLine(a);

  21. }

  22. public static void ProgramMothod_2(int a, int b) {

  23. Console.WriteLine(a+b);

  24. }

  25. }

使用泛型委托
 
  1. delegate void VoidDelegate_3<T>(T a, T b);

  2. internal class Program

  3. {

  4. static void Main(string[] args)

  5. {

  6. VoidDelegate_3<string> voidDelegate_3 = new VoidDelegate_3<string> (ProgramMothod_3);

  7. VoidDelegate_3<int> voidDelegate_4 = new VoidDelegate_3<int>(ProgramMothod_2);

  8. Console.ReadKey();

  9. }

  10. public static void ProgramMothod_2(int a, int b) {

  11. Console.WriteLine(a+b);

  12. }

  13. public static void ProgramMothod_3(string a, string b)

  14. {

  15. Console.WriteLine(a + b);

  16. }

  17. }

使用委托作为方法参数
 
  1. static void Main(string[] args)

  2. {

  3. ProgramMothod_3(3, 4, ProgramMothod_2);

  4. Console.ReadKey();

  5. }

  6. public static int ProgramMothod_2(int a, int b)

  7. {

  8. return a + b;

  9. }

  10. public static void ProgramMothod_3(int w,int y,VoidDelegate_4 voidDelegate_4)

  11. {

  12. int temp = voidDelegate_4(w,y);

  13. Console.WriteLine(temp);

  14. }

  15. }

使用 Action和Func委托

方法的返回类型和名字千千万万,无法对每个方法都去定义对应的委托,.net为了方便使用委托,定义了两个泛型委托。

Action

Action委托表示一个void返回类型的方法

Func
Func委托表示一个带返回类型的方法

至多可以传递16种不同类型的参数和一个返回类型。返回类型放在<>最后一个。

 
  1. static void Main(string[] args)

  2. {

  3. Action action1 = new Action(ProgramMothod_1);

  4. Action<int, int> action = new Action<int, int>(ProgramMothod_2);

  5. Func<int> func = new Func<int>(ProgramMothod_4);

  6. Func<int,int,int> func1 =new Func<int, int, int> (ProgramMothod_5);

  7. Console.ReadKey();

  8. }

  9. public static void ProgramMothod_1() {

  10. }

  11. public static void ProgramMothod_2(int a, int b) {

  12. Console.WriteLine(a+b);

  13. }

  14. public static int ProgramMothod_4()

  15. {

  16. return 1;

  17. }

  18. public static int ProgramMothod_5(int a ,int b)

  19. {

  20. return a+b;

  21. }

  22. }

 委托的多播

1.委托对象可使用 "+" 运算符进行合并。

2."-" 运算符可用于从合并的委托中移除组件委托

3.只有相同类型的委托可被合并

 
 
  1. internal class Program

  2. {

  3. static void Main(string[] args)

  4. {

  5. Action totalAction;

  6. Action action1 = new Action(ProgramMothod_1);

  7. Action action2 = new Action(ProgramMothod_2);

  8. totalAction = action1;

  9. totalAction += action2;

  10. totalAction();

  11. Console.ReadKey();

  12. }

  13. public static void ProgramMothod_1() {

  14. }

  15. public static void ProgramMothod_2()

  16. {

  17. }

使用委托作为方法的参数
 
  1. internal class Program

  2. {

  3. static void Main(string[] args)

  4. {

  5. ProgramMothod_1(ProgramMothod_2);

  6. Console.ReadKey();

  7. }

  8. public static void ProgramMothod_1(Action action) {

  9. action();

  10. }

  11. public static void ProgramMothod_2()

  12. {

  13. Console.WriteLine("11");

  14. }

事件

1.事件基于委托的,可以为任何一种委托提供一种发布\订阅机制。(类似委托多播)
2.使用event关键字将一个委托类型定义为事件  事件就是委托的一个对象

 
  1. internal class Program

  2. {

  3. static void Main(string[] args)

  4. {

  5. Heater heater = new Heater();

  6. heater.BoilEvent += Heater1;

  7. heater.BoilEvent += Heater2; //添加事件

  8. heater.BoilWater();//执行事件

  9. }

  10. public static void Heater1(int x) {

  11. Console.WriteLine("水已经{0}度了,可以用茶杯接水了",x);

  12. }

  13. public static void Heater2(int x)

  14. {

  15. Console.WriteLine("水已经{0}度了,可以用大桶接水了", x);

  16. }

  17. }

  18. //烧开水事件 类

  19. public class Heater

  20. {

  21. private int temperature;//水温

  22. public delegate void BoilHandle(int x);//声明关于事件的委托

  23. public event BoilHandle BoilEvent;//声明水要烧开的事件

  24. public void BoilWater()

  25. { //烧水的方法

  26. for (int i = 0; i <= 100; i++)

  27. {

  28. temperature = i;

  29. if (temperature > 96)

  30. {

  31. if (BoilEvent != null)

  32. {

  33. BoilEvent(temperature);

  34. }

  35. }

  36. }

  37. }

  38. }

普通匿名函数

1.针对委托的使用

2.可以快捷的使委托实例化。
3.不建议再使用匿名函数,C#3.0后使用lambda表达式替代匿名函数

匿名函数基本写法:

 
 
  1. 匿名函数的写法

  2. :

  3. class Program

  4. {

  5. delegate int MyDelegate(int a, int b);

  6. static void Main(string[] args)

  7. {

  8. MyDelegate md = delegate(int a, int b) { return a + b; };

  9. int sum = md(1,2);

  10. Console.WriteLine(sum);

  11. }

  12. }

事件与普通匿名函数
 
  1. nternal class Program

  2. {

  3. static void Main(string[] args)

  4. {

  5. Heater heater = new Heater();

  6. heater.BoilEvent += delegate (int x) //添加匿名函数

  7. {

  8. Console.WriteLine("水已经{0}度了,可以用茶杯接水了", x);

  9. };

  10. heater.BoilEvent += delegate (int x) //添加匿名函数

  11. {

  12. Console.WriteLine("水已经{0}度了,可以用大桶接水了", x);

  13. };

  14. heater.BoilWater();//执行事件

  15. }

  16. }

  17. public class Heater

  18. {

  19. private int temperature;//水温

  20. public delegate void BoilHandle(int x);//声明关于事件的委托

  21. public event BoilHandle BoilEvent;//声明水要烧开的事件

  22. public void BoilWater()

  23. { //烧水的方法

  24. for (int i = 0; i <= 100; i++)

  25. {

  26. temperature = i;

  27. if (temperature > 96)

  28. {

  29. if (BoilEvent != null)

  30. {

  31. BoilEvent(temperature);

  32. }

  33. }

  34. }

  35. }

  36. }

   

lambda表达式
1.普通匿名函数的升级版本  (箭头函数)

2.比普通匿名函数更为简洁,数据类型可以不用写 

 
  1. class Program

  2. {

  3. delegate int MyDelegate(int a, int b);

  4. static void Main(string[] args)

  5. {

  6. MyDelegate md = (a,b)=>{return a+b;};

  7. int sum = md(1, 2);

  8. Console.WriteLine(sum);

  9. }

  10. }

   事件与lambda表达式

 
  1. internal class Program

  2. {

  3. static void Main(string[] args)

  4. {

  5. Heater heater = new Heater();

  6. heater.BoilEvent += x =>

  7. {

  8. Console.WriteLine("水已经{0}度了,可以用茶杯接水了", x);

  9. };

  10. heater.BoilEvent += x=> //添加匿名函数

  11. {

  12. Console.WriteLine("水已经{0}度了,可以用大桶接水了", x);

  13. };

  14. heater.BoilWater();//执行事件

  15. Console.ReadKey();

  16. }

  17. }

  18. public class Heater

  19. {

  20. private int temperature;//水温

  21. public delegate void BoilHandle(int x);//声明关于事件的委托

  22. public event BoilHandle BoilEvent;//声明水要烧开的事件

  23. public void BoilWater()

  24. { //烧水的方法

  25. for (int i = 0; i <= 100; i++)

  26. {

  27. temperature = i;

  28. if (temperature > 96)

  29. {

  30. if (BoilEvent != null)

  31. {

  32. BoilEvent(temperature);

  33. }

  34. }

  35. }

  36. }

  37. }

  .运算符重载
1.含义

  是对已有的运算符重新定义新的运算规则,以适应不同的数据类型

 
    特点:
              1.运算符重载的声明方式:operator 关键字
              2.必须用public修饰且必须是类的静态的方法
              3.重载运算符的方法 不用主动调用 只要使用重载的运算符就相当调用了方法
              4.运算符只能采用值参数,不能采用ref或out参数
              5.重载运算符的返回值不一定必须是自己,但一定不能是void

 

 
  1. 运算符 可重载性

  2. ! ++、--、 可以重载这些一元运算符

  3. +、-、*、/、%、&、| 可以重载这些二元运算符

  4. ==、!=、<、>、<=、>= 可以重载比较运算符,必须成对重载

  5. &&、|| 不能重载条件逻辑运算符,但可以使用能够重载的&和|进行计算

  6. +=、-=、*=、/=、%=、&=、|=、^=、<<=、>>= 不能显式重载赋值运算符,在重写单个运算符如+、-、%时,它们会被 隐式重写

  7. =、.、?:、->、new、is、sizeof、typeof () [] 不能重载这些运算符

   

  +     -     *  /   %     ++   --   !

 
  1. public static Student operator +(Student stu1,Student stu2)

  2. {

  3. return new Student(stu1.Age + stu2.Age, stu1.Name + stu2.Name);

  4. }

  5. public static Student operator -(Student stu1, Student stu2)

  6. {

  7. return new Student(stu1.Age - stu2.Age, stu1.Name + stu2.Name);

  8. }

  9. public static Student operator ++(Student stu1)

  10. {

  11. stu1.Age++;

  12. stu1.Height++;

  13. return stu1;

  14. }

  15. public static bool operator !(Student stu1)

  16. {

  17. if (stu1.Age < 20)

  18. {

  19. return !false;

  20. }

  21. else {

  22. return !true;

  23. }

  24. }

  25. public static Student operator &(Student stu1,Student stu2)

  26. {

  27. if (stu1.Age < 20 && stu2.Age<10)

  28. {

  29. return new Student(stu1.Age + stu2.Age);

  30. }

  31. else

  32. {

  33. return new Student(stu1.Age - stu2.Age);

  34. }

  35. }

C# 异常处理

含义:异常是在程序执行期间出现的问题。例如除零错误、空引用访问、文件不存在等

C# 异常处理四个关键字:trycatchfinally 和 throw

  • try:一个 try 块包括一块要被检测异常的代码块
  • catch:表示对异常的捕获和处理。
  • finally:不管异常是否存在都会执行。
  • throw:当问题出现时,程序抛出一个异常。使用 throw 关键字来完成。

格式:


try
{
   // 引起异常的语句
}
catch( ExceptionName e1 )
{
   // 错误处理代码
    throw e1;
}
finally
{
   // 要执行的语句
}

C# 中的异常

在C#中,异常分为两种类型:系统异常和自定义异常

C# 中的系统异常类主要继承与 System.Exception 类

 常见的系统异常类

    ArithmeticException:算术异常,如除以零。
    NullReferenceException:空引用异常,当试图在引用为null的对象上调用方法或访问属性时引发。
    IndexOutOfRangeException:索引越界异常,当数组或集合的索引超出范围时引发。
系统异常使用

 //0做为被除数
            int result = 0;
            
            try
            {
                int num1 = 10;
                int num2 = 0;
                result = num1 / num2;
 
            }
            catch (SystemException e)
            {
                Console.WriteLine("异常错误为: {0}", e);
                //throw e;
            }
            finally
            {
 
                Console.WriteLine(result);
            }
 
            数组越界
            //int[]intArray =new int[3];
 
            //try
            //{
            //     intArray[4] = 10;
 
            //}
            //catch (SystemException e)
            //{
            //    Console.WriteLine("异常错误为111: {0}", e);
            //  //  throw e;
            //}
            //finally
            //{
 
            //    Console.WriteLine("1");
            //}

 多个 catch 语句捕获不同类型的异常,以防 try 块在不同的情况下生成多个异常

try
{
 
    //using语句可用于确保在使用完资源后释放它,以避免资源泄漏  等同于reader.Dispose() 释放资源
    using (StreamReader reader = new StreamReader("file.txt"))
    {
        string content = reader.ReadToEnd();
       
    } 
}
catch (FileNotFoundException ex)
{
    Console.WriteLine("文件不存在:" + ex.Message);
}
catch (IOException ex)
{
    Console.WriteLine("IO错误:" + ex.Message);
}
finally
{
    Console.WriteLine("处理结束。");
}

自定义异常处理

  //对于People 对象年龄限制的异常处理
static void Main(string[] args)
        {
 
            Peopele peopele = new Peopele();
            try
            {
                peopele.Age = 140;
            }
            catch (SystemException e)
            {
                Console.WriteLine("TempIsZeroException: {0}", e.Message);
            }
            finally {
                Console.WriteLine("年龄:{0}符合要求",peopele.Age);
            }
       
 
            Console.ReadKey();
        }
    }
   
 
 
//对于People 对象年龄限制的异常处理
    public class Peopele
    {
        private int _age;
        public int Age { 
            get { return _age; } 
            set {
                if (value < 0 || value > 100)
                {
                    throw (new  SystemException("年龄不符合要求"));
                }
                else {
 
                    _age = value;
                }
            } }
    
       
 
    }  

C# 预处理器指令

含义:

预处理器指令是指编译器在实际编译开始之前对信息进行预处理。通常用于简化源程序在不同的执行环境中的更改和编译

1.所有的预处理器指令都是以标识符 # 开始

2.预处理器指令不是语句,因此它们不需要以分号;结尾

预处理指令符号:

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

举例理解:

在程序调试和发布程序时,有些代码是只在调试时才执行  在程序发布时就可能被注释  但是通常我们不用注释的方式来解决 而是用预处理指令完成

定义符号 #define 和 取消定义符号 #undef    可用于 #if 等编译指令的条件

//要写在文件开头
#define DebugModel
#undef DebugModel
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
namespace ConsoleApp1
{
    internal class Program
    {
        static void Main(string[] args)
        {
 
         
          
          #if  DebugModel
                Console.WriteLine("调试模式");
            #endif
            Console.ReadKey();
        }
    }

条件编译
  • #if:打开条件编译,其中仅在定义了指定的符号时才会编译代码。
  • #elif:关闭前面的条件编译,并基于是否定义了指定的符号打开一个新的条件编译。
  • #else:关闭前面的条件编译,如果没有定义前面指定的符号,打开一个新的条件编译。
  • #endif:关闭前面的条件编译。
  • 条件编译指令的用法和 C# 中的条件判断语句 if、elif 和 else 语句差不多
  • #define condition2       // 定义 condition 字符
    using System;

    public class ExampleProgram
    {
        static void Main(string[] args)
        {
            #if (condition)
                Console.WriteLine("condition is defined");
            #elif (condition2)      // 测试 condition2 是否为真
                Console.WriteLine("condition2 is defined");
            #else
                Console.WriteLine("condition is not defined");
            #endif
                Console.ReadLine();
        }
    }


定义区域符号 #region 和 #endregion 分别表示启动区域和结束区域。这两个预处理器指令来定义可在大纲中折叠的代码区域

错误和警告信息

#error:使用指定的消息生成编译器错误

#warning:使用指定的消息生成编译器警告。

 static void Main(string[] args)
        {
            // 错误:此方法中的弃用代码。
            #error 以下代码即将废弃
            Console.WriteLine("你好");

           

            #warning 以下代码即将废弃
            Console.WriteLine("你好");

        }

#line:更改用编译器消息输出的行号

#line 200 "文件名"
        int i;
        int j;
#line default       
        char c;
        float f;
 
 
 
#line 200 指令将下一行的行号强制设为 200
#line default 指令将行号恢复至默认行号

预处理器指令的用途

有利于项目的调式和运行。例如说可以使用条件编译指令控制程序流的执行,在实际的项目中表现为多版本代码片段控制。
在代码的调式阶段,可以使用错误和警告信息指令来禁止编译不属于本功能的额外代码。
使用定义区域指令可以很好折叠和隐藏指定区域的代码片段。开发者可以更好的集中处理关键代码,在有着多个代码区域的项目十分的方便。
 

C#中的IO(Input/Output)操作包括读取和写入文件、读取和写入流、以及操作目录和文件夹等。这些操作都可以通过System.IO命名空间中的类实现。

文件操作
File类
File类提供了对文件的创建、读取、写入、复制、移动、重命名删除等操和作。

File创建文件

   public static bool FileCreate(string filePath) {
            //File类 创建文件
            try
            {
                //"D:\\myFile.txt"    @"D:\myFile.txt"    一致
                //判断文件是否存在
                if (!File.Exists(filePath))
                {
                    FileStream fileStream = File.Create(filePath);
                    fileStream.Close();
                    return true;
                }
                else
                {
                    Console.WriteLine("文件存在");
                }
            }
            catch (Exception e)
            {
                Console.WriteLine("文件创建功能的异常:+" + e.Message);
            }
            return false;
 
        }

File写入文件

写入文件可以使用下面方式:
1. File.WriteAllText(FilePath,String)
2. File.WriteAllLines(FilePath,String[])
 
 
前面写入的是一个字符串,后面两种写入的是一个字符串数组。
 
使用 File.WriteAllText 或 File.WriteAllLines 方法时,如果指定的文件路径不存在,会创建一个新文件;如果文件已经存在,则会覆盖原文件。
 
第一种:指定字符串的写入
            static void Main(string[] args)
            {
                string filePath = @"E:\myFile.txt";
                string content = "读取读取读取读取读取读取";
             
                //File.WriteAllText(filePath, content);
           
     
                Console.ReadKey();
            }
        }
 
第二种:字符串数组的写入
 static void Main(string[] args)
        {
            string filePath = @"E:\myFile.txt";
            string[] contentArr = { "dddd", "eeeeee" };
 
       
            //File.WriteAllLines(filePath, contentArr);
         
 
            Console.ReadKey();
        }
 

File读取文件

读取文件可以使用下面方式:
 
1.File.ReadAllText(FilePath)
2.File.ReadAllLines(FilePath)
 
  
以字符串接收方式
static void Main(string[] args)
        {
            string path = @"E:\myFile.txt";
            string content = File.ReadAllText(path);
            Console.WriteLine(content);
            Console.ReadKey();
        }
 
 
以字符串数组接收的方式
 
  static void Main(string[] args)
        {
            string path = @"E:\myFile.txt";
            //string[] content = File.ReadAllLines(path); 
            string[] content = File.ReadAllLines(path, Encoding.UTF8);
            Console.ReadKey();
        }

StreamReader和StreamWriter类
StreamReader和StreamWriter类用于读取和写入文本文件。

StreamWriter写数据

                string path = @"D:\myFile.txt";
                StreamWriter streamWriter = new StreamWriter(path);
                streamWriter.WriteLine("ABC");
                streamWriter.WriteLine("DDD");
                streamWriter.Write("HAHAH");
                streamWriter.Write("ABVV");
                streamWriter.Close();

StreamReader读数据

string path = @"E:\myFile.txt";
StreamReader sr = new StreamReader(path, Encoding.UTF8);
string content = sr.ReadToEnd();
Console.WriteLine(content);
sr.Close();
 
//思考题  读取的字符串 如何转化成数组

追加数据

  string path = @"D:\myFile.txt";
 
            if (!File.Exists(path))  //检查文件是否存在
            {
                FileStream fs = new FileStream(path, FileMode.Create, FileAccess.Write);  //创建
                StreamWriter sw = new StreamWriter(fs);
                sw.WriteLine("input text");  //写入内容,自定义
             
                sw.Close();
                fs.Close();
            }
            else
            {
                FileStream fs = new FileStream(path, FileMode.Append, FileAccess.Write);  //追加写入
                StreamWriter sw = new StreamWriter(fs);
                sw.WriteLine("567");  //写入内容,自定义
            
                sw.Close();
                fs.Close();
            }

           
删除
 
 string newFilePath = @"E:\myFile_new.txt";
            File.Delete(newFilePath);
 
 
移动
 
string sourceFilePath = @"E:\myFile.txt";
            string destinationFilePath = @"D:\myFile.txt";
            File.Move(sourceFilePath, destinationFilePath);
 
 
 
 
复制
string sourceFilePath = @"E:\myFile.txt";
            string destinationFilePath = @"E:\myFile_copy.txt";
            File.Copy(sourceFilePath, destinationFilePath);

  • 19
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值