zl程序教程

您现在的位置是:首页 >  其他

当前栏目

C#基础到入门(一篇就够了)(三)

2023-03-14 22:55:03 时间

🍺 字符串

ContainsContains
RemoveLastIndexOf
public string Remove(( int startIndex)/ (int startIndex, int count ))public int LastIndexOf( (string/char) value )
CopyToPadLeft
从 string 对象的指定位置开始复制指定数量的字符到 Unicode 字符数组中的指定位置。补充左边长度:.PadLeft(2, ‘0’)
FormatPadRight
把指定字符串中一个或多个格式项替换为指定对象的字符串表示形式。补充右边长度:.PadRight(2, ‘0’)
IndexOfReplace
返回指定 Unicode 字符在当前字符串中第一次出现的索引,索引从 0 开始。替换文字:stringObj.replace(“终古”,“中国”);
InsertSplit
返回一个新的字符串,其中,指定的字符串被插入在当前 string 对象的指定索引位置。返回一个字符串数组,包含当前的 string 对象中的子字符串,子字符串是使用指定的 Unicode 字符数组中的元素进行分隔的。
JoinToLower
连接一个字符串数组中的所有元素,使用指定的分隔符分隔每个元素。把字符串转换为小写并返回。
SubstringToUpper
string substr = str.Substring(23);把字符串转换为大写并返回。
Trim
移除当前 String 对象中的所有前导空白字符和后置空白字符。

🍺🍺StringBuilder、重载、递归

⌨⌨StringBuilder


  • 在System.Text命名空间下
    • 所以使用时,需要先引入这个命名空间
using System.Text;
  • 如果不引入,可以直接写:
System.Text.StringBuilder strB = new System.Text.StringBuilder();
  • 使用时,先要new
StringBuilder stringB = new StringBuilder();
  • 追加字符串
//追加字符串
stringBuilder.Append("天气好晴朗");
  • 什么时候用StringBuilder而不用string
    • 字符串需要经常修改的时候

⌨⌨⌨方法的重载

  • 同一个类里面,方法名一样,但参数不一样
    • 参数的数据类型不一样
    • 参数的个数不一样
    • 参数的数据类型不一样,个数也不一样
  • 参数个数和类型都一样,但返回值类型不一样,不能算做重载❌
class Funs
{
  public string Fun(string a, string b)
  {
      return "a+b";
  }
  public int Fun(int a, int b)
  {
      return a + b;
  }
}
Funs funs = new Funs();
int a = funs.Fun(1, 1);
string b = funs.Fun("2", "2");
string c = string.Format("{0},{1}", a, b);
Console.WriteLine(c);
Console.Read();

9.png

image.png

⌨⌨递归

  • 方法自己调用自己
  • 多个方法之间来回调用
  • 使用递归时一定要有出口
  • 使用递归时,一定概要慎重慎重再慎重…

⌨⌨⌨构造函数

执行的时机

new对象()的时候调用

构造函数一般都是public

因为一旦构造函数被设置为了private,那么外界就无法new这个

构造函数没有返回值

也不能写返回值类型

构造函数的名字必须和类名保持完全的一致

构造函数是不能像普通方法一样被直接调用的

关于系统会不会自动创建一个空参空方法体的构造给你

如果一个类没有构造函数

那么系统会自动写一个空参数空方法体的构造函数

如果有构造函数

那么系统就不会帮你自动创建

构造函数可以有参、也可以无参

构造函数是可以重载的

如果想在执行当前构造函数之前,先执行其他的构造函数

当前构造函数(…) : this(传实参)

class Person
{
 private int age;
 private string name;

 public Person(int age)
 {
     this.age = age;
     Console.WriteLine(age);
 }
 public Person(string name) : this(18)
 {
     this.name = name;
     Console.WriteLine(name);
 }

 public Person(int age, string name) : this("xian")
 {
     Console.WriteLine("我是性别,年龄!");
 }
}

static void Main(string[] args)
{
 Person body = new Person(128, "alll");

 Console.Read();
}

image.png

🍺🍺🍺多态

⌨关于父类空参数构造函数的调用说明


首先,先要明确一点

子类在实例化的时候,必会调用父类的构造函数

子类在声明构造函数的时候,要想办法调用父类的构造

如果父类是空参数的构造函数 : base()

可以不写:base()

系统会默认调用父类的空参数构造

如果父类是有参数的构造函数,那么一定概要通过:base的方式调用,传参

关于VS自动生成类构造函数

右键类名

点击快速修复或重构

点击生成构造

public class Person
{
    public string name;

    public Person(string name)
    {
        this.name = name;
        Console.WriteLine(name);
    }

    public void Say()
    {
        Console.WriteLine("你在干什么!");
    }
}
public class Person1:Person
{
    public Person1(string name):base(name)
    {
    }
    public new void Say()
    {
        Console.WriteLine("弄啥呢!");
    }
}
public class Person2:Person1
{
    public Person2(string name) : base(name)
    {
    }
    public new void Say()
    {
        Console.WriteLine("搞啥呢!");
    }
}
static void Main(string[] args)
{
    Person p = new Person("1");
    p.Say();
    Person1 p1 = new Person1("2");
    p1.Say();
    Person2 p2 = new Person2("3");
    p2.Say();
    PersonFun(p2);
    Console.ReadLine();
}
public static void PersonFun(Person person)
{
    person.Say();
}

image.png

⌨子类方法的覆盖

前提条件:父类中有一个public函数,子类中没有该函数

因为子类中并没有该函数,所以调用必是父类的

前提条件:子类里已经有了该函数,父类里面也有该函数

此时,子类对象调用子类的该函数,父类对象调用父类的该函数

这种子类函数,可以称之为覆盖

子类在书写该函数的时候,规范的写法应该是:

[访问修饰符] new 返回值类型 函数名(参数列表)

覆盖:子类也有该函数了,以后调用的时候就调用子类的该函数

10.png

⌨子类方法的重写【表现出多态】

那么父类的该函数必须是一个虚函数

[访问修饰符] virtual 返回值类型 函数名(参数列表)

子类该怎么重写

[访问修饰符] override 返回值类型 函数名(参数列表)

重写:把子类和父类的该函数都重新写了一遍,有的新的内容

此时,子类的对象,无论是不是转换成了父类的类型,都会执行重写后的该函数

关于VS自动生成类重写函数

右键类名

点击快速修复或重构

点击生成重写

public class Person
{
   public string name;

   public Person()
   {
   }

   public Person(string name)
   {
       this.name = name;
   }

   public virtual void Say()
   {
       Console.WriteLine("我是父类的方法");
   }


}
public class Person1 : Person
{
   public Person1(string name)
   {
   }

   public override void Say()
   {
       Console.WriteLine("我是字类的方法");
   }
}
static void Main(string[] args)
{
   Person1 p1 = new Person1("我是字类");
   p1.Say();
   Person p = new Person1("我是父类");
   p.Say();

   Console.ReadLine();
}

⌨⌨所有类的最终基类:Object

  • 所以,所有类都可以重写Object类中的虚方法
  • Object的虚方法有三个:
    • Equals:描述对象与对象之间是否相等
    • GetHashCode:将一个对象编程一串数字
    • ToString:将一个对象转换为一个字符串

image.png

⌨⌨抽象方法

抽象方法的关键词abstruct

abstruct 返回值类型(参数列表)

抽象方法必须要放在抽象类里面

抽象方法没有方法体: [访问修饰符] abstruct 返回值类型 方法名(形参列表);

抽象方法的访问修饰符不能是private

抽象类即可以放抽象方法,也可以放普通方法

抽象方法必须在子类中全部实现

除非子类也是一个抽象类,那么可以先不实现该抽象方法

抽象方法和虚方法最大的区别

抽象方法必须其派生类中得以实现

而虚方法不是一定要在其派生类去重写

无论是虚方法还是抽象方法,子类进行了重写【实现】

那么子类的子类依旧可以继续重写

抽象类不能用sealed关键词修饰

总结:override可以重写哪些方法呢?

带有virtual、abstruct、override关键词的方法

代码:

//抽象类
public abstract class Person
{
    public void Fun(string name)
    {
        Console.WriteLine(name);
    }
    public abstract void Say();
}
public class Person1 : Person
{
    public override void Say()
    {
        Console.WriteLine("asd");
    }
}
static void Main(string[] args)
{

    Person1 a = new Person1();
    a.Say();
    Console.Read();
}

⌨⌨sealed关键词

sealed关键词修饰的类称之为密封类

语法:sealed class 类名

密封类是不能被别的类继承的

密封方法

sealed关键词修饰的重写的方法,称之为密封方法

语法:sealed override 返回值类型 方法名(参数列表)

密封方法无法再次被其子类重写

代码:

public class Person
{
public virtual void Fun()
{
  Console.WriteLine(1);
}
}
public class Person1 : Person
{
public sealed override void Fun()
{
  Console.WriteLine(2);
}
}
public class Person2 : Person1
{
//这里报错 因为续承的Person1是密封函数
public override void Fun()
{
  base.Fun();
}
}
static void Main(string[] args)
{

Person a = new Person1();
a.Fun();

Console.Read();

}

⌨⌨静态类

关键词 static

静态成员

成员:字段、属性、方法

静态:跟对象没有任何关系,只跟类有关系

静态成员在何时开辟的内存

第一次访问这个类的时候【第一次用到这个类的时候】

比如:用这个类名去实例化一个对象

比如:用这个类型去访问一个静态字段

静态成员在何时释放内存

在程序结束的时候才会释放

普通的实例成员,每有一个对象,就有一个该成员

而静态成员,跟对象没有关系,所以无论有多少个对象,静态成员都只有一个

例: 实例成员【name】,每有一个人,就会有对应的一个名字

而静态成员【Population】,跟对象没有关系,无论有多少个实例对象,人口数量只有一个

静态方法中是不可以访问非静态的成员的

不能访问非静态的字段、属性

不能调用非静态的方法

非静态方法中是可以访问静态成员的

能访问静态的字段、属性

能调用静态的方法

静态方法是可以有重载

静态类

静态的成员可以放在静态类中,也可以放在非静态类中

静态类中只能存在静态成员,不能存在非静态的成员

静态类是不能进行实例化的

静态构造函数

只有一种写法

static 类名()

静态构造函数必须无参数

静态构造函数在什么时候才会调用

静态构造函数在程序运行期间只会执行一次

在第一次访问该类的时候调用

用这个类去new一个对象

用这个类去访问某个静态成员

用这个类去调用某个静态方法

如果有继承关系

静态构造函数的执行顺序是:

先执行子类的静态构造,再执行父类的静态构造

先子后父

静态构造有什么作用

一般用于对静态成员进行初始化

代码

class Person
{
    public static float age=88;
    public static void Fun()
    {
        Console.WriteLine("我是父静态类!");
    }
    static Person()
    {
        Console.WriteLine("我是基静态类!");
    }
}

class Per : Person
{
    static Per()
    {
        Console.WriteLine("我是子静态类!");
    }
}
static void Main(string[] args)
{
    Per p = new Per();
    Console.WriteLine();
    Console.ReadLine();
}

image.png

集合、栈、堆、队列、字典 ✍🔤🔤🔤

1、集合~范型(命名空间using System.Collections.Generic;)


1.1、ArrayList

代码:

//实例化动态数组
ArrayList score = new ArrayList();
//向动态数组中添加元素
score.Add(90);
score.Add(85.5f);
score.Add("English:100");

int[] array = { 90,80,70 };
//向动态数组中批量添加元素
score.AddRange(array);
//向动态数组中插入元素
score.Insert(2, "Math:80.5");
//删除动态数组中的元素
score.Remove(85.5f);
//删除的是单个约束,如果动态数组中没有该元素,就忽略
score.Remove(90);
//根据下标移除动态数组中的元素
score.RemoveAt(0);

score.AddRange(new string[] { "A", "B", "C", "A" });
//批量删除元素
score.RemoveRange(2, 3);
//如果数组中没有该下标所对应的元素,则也会出现越界异常
Console.WriteLine(score[1]);
//数组元素翻转
score.Reverse();    
//一般想要删除某个元素,会先进行判断是否存在
bool containsA = score.Contains("A");
Console.WriteLine("containsA:" + containsA);
//判断数组中是否包含某个元素
if(score.Contains("A"))
{
  score.Remove("A");
}
Console.WriteLine("Count:" + score.Count);
//给一个元素的值,查该值在动态数组中的下标
Console.WriteLine("IndexOf:" + score.IndexOf(790));
score.Clear();

score.AddRange(new float[] { 1.1f,5.7f,4.5f,9.8f,3,2,1});
//从小到大排序
score.Sort();
//清空动态数组
//score.Clear();
Console.WriteLine("-------------");
for (int i = 0; i < score.Count; i++)
{
  Console.WriteLine(score[i]);
}
Console.WriteLine("-------------");
foreach (var item in score)
{
  Console.WriteLine(item);
}

1.2、List

代码:

//初始化范型集合
List<int> list = new List<int>();

//添加元素
list.Add(200);
list.Add(250);
list.Add(280);
//批量添加元素
list.AddRange(new int[] { 1,3,5,6,7,9 });
//移除某个元素
list.Remove(280);
//通过下标移除某个元素
list.RemoveAt(0);
list.RemoveAt(0);
//批量删除
list.RemoveRange(0, 3);
int index = list.IndexOf(9);
Console.WriteLine(index);
Console.WriteLine("-----------");
foreach (var item in list)
{
   Console.WriteLine(item);
}

2、栈(Stack )


  • 说明:后进先出

代码:

eg:非范型为例😥

Object<=Stack stack = new Stack();
//进栈
stack.Push("我是第一个进去的");
stack.Push("我是第二个进去的");
stack.Push("我是第三个进去的");
//出栈
Console.WriteLine(stack.Pop());
Console.WriteLine(stack.Pop());
Console.WriteLine(stack.Pop());
Console.Read();
//返回栈顶的元素Peek();

image.png

常用方法

image.png

Stack.TryPeek(T) 方法

返回一个值,该值指示 Stack 的顶部是否有对象;如果有,则将其复制到 result 参数。 不从 Stack 中删除对象。

public bool TryPeek (out T result);

返回

Boolean

如果 Stack 的顶部有对象,则为 true;如果 Stack 为空,则为 false。

Stack.TryPop(T) 方法

public bool TryPop (out T result);

返回一个值,该值指示 Stack 的顶部是否有对象;如果有,则将其复制到 result 参数,并从 Stack 中删除它。

返回

Boolean

如果 Stack 的顶部有对象,则为 true;如果 Stack 为空,则为 false。

3、堆(heaps)

😀😀😀略略略

4、队列(Queue)


说明:先进先出

eg:进列

image.png

eg:出列

image.png

代码:

eg:非范型为例😥

Queue queue = new Queue();
//进列
queue.Enqueue("我是第一个进去的");
queue.Enqueue("我是第二个进去的");
queue.Enqueue("我是第三个进去的");
//出列
Console.WriteLine(queue.Dequeue());
Console.WriteLine(queue.Dequeue());
Console.WriteLine(queue.Dequeue());
Console.Read();

image.png

常用方法:

image.png

5、字典(Dictionary<string,int>)


image.png

代码:

Dictionary<string, int> dis = new Dictionary<string, int>();
dis.Add("我是第一个进去的", 1);
dis.Add("我是第二个进去的", 2);
dis.Add("我是第三个进去的", 3);
Console.WriteLine(dis.Values);
Console.WriteLine(dis.ContainsValue(2));
Console.WriteLine(dis.ContainsValue(3));
Console.Read();

6、常见的接口


image.png

🍺🍺🍺🍺单例、接口和范型

1、单例


  • 如果一个对象在声明时直接实例化【new】。
  • 在访问这个类的时候调用
  • 实例化的时间点最早,在静态构造之前就执行了

image.png

2、接口

接口相比类,最大的不同之处在于,只有定义没有实现

接口相当于一堆骨架,实现接口的类,用于填充骨架上的肉

接口不能进行实例化,只能被类或其他接口实现

如即继承类,又实现接口时,类要放在最前面,接口放在后面

eg:

class Person1:Person,jiankou1,jiekou2

11.png

2.1、接口和抽象类的对比

相同点

两者都不能被实例化

两者都包含了由其他类或结构继承或实现的抽象成员不同点

不同点

抽象类当中除了拥有抽象成员外还可以拥有非抽象成员;而接口中所有的所有成员都是抽象的

抽象成员可以使用修饰符修饰,接口当中接口成员访问级别是默认不可修改的,并且默认是public

接口当中不可以包含构造方法,析构方法,静态成员以及常量

C#类只支持单继承,接口支持多支持

3、范型

范型类的构造函数不用写范型类

有些时候重载的方法只有参数类型不同,其他的都一样,这时就可以使用泛型。

泛型:需要用户自己传过来的一个数据类型

平时方法里传递的是参数,是变量,参数传递用的是小括号()。

而泛型传递的是数据类型,泛型传递用的尖括号<>

泛型定义之后,一定要用,不然就没有意义

泛型都在方法的哪里用?

定义参数

在方法体呢使用泛型定义局部变量口

设置返回值类型是一个泛型。给泛型添加约束

给范型舔加约束

方法名(参数列表)where 泛型:约束内容

方法名(参数列表)where 泛型A:约束内容1,约束内容2 where 泛型B:约束内容3

关于泛型方法的重载

如果泛型的个数不同,可以重载

如果泛型的个数相同,但约束不同,不可以重载

关于泛型类和泛型接口

class 类名<T,F>

类中的字段类型、方法参数、方法返回值,都可以使用类中的泛型

interface 接口名< T >

image.png

代码:

public class fanxing
{
  
}
public static void FX<T>(T sex, T age)
{
   T temp = sex;
   sex = age;
   age = temp;
   Console.WriteLine(age);
}
public static void FX<T>(T sex, T age, T a)
{
   T temp = sex;
   sex = age;
   age = temp;
   Console.WriteLine(age);
}

static void Main(string[] args)
{
  FX<int>(7,8);
  FX<float>(7,8);
   Console.ReadLine();
}
- 范型方法的范型重载
eg 代码:
```代码
public static void faning<T>()
{

}
public static void faning<T,F>()
{

}
public static void faning<T,F,U>()
{

}

static void Main(string[] args)
{
   faning<>

}

12.png

🍺🍺🍺🍺委托与事件

1、委托(delegate)


2.1常见委托类型

  • 什么是委托:相当于中介
  • 委托的别名:代理、句柄
  • 委托是自定义类型
  • 委托是引用类型

代码eg:

eg:非范型为例😥

//定义委托
delegate void weituo(float momey);
class p1
{
    public void zhao1(float momey)
    {
        Console.WriteLine("中介一需要:"+momey+"$");
    }
    public void zhao2(float momey)
    {
        Console.WriteLine("中介二需要:"+ momey + "$");
    }
    public void zhao3(float momey)
    {
        Console.WriteLine("中介三需要:"+ momey + "$");
    }
    public void zhao4(float momey)
    {
        Console.WriteLine("中介四需要:"+momey + "$");
    }
}

internal class Program
{
    static void Main(string[] args)
    {
        p1 p = new p1();

        weituo we;

        we = p.zhao1;
        we += p.zhao2;
        we += p.zhao3;
        we += p.zhao4;
        we(1232143);
        Console.Read();
    
    }
}

2.2系统委托类型

  1. 无返回值系统委托 Action<>

代码eg:

eg:😥

class p1
{
    public void wcs()
    {
        Console.WriteLine("我是无参数的中介需要:" + "18456456456456"+ "$");
    }
    public void zhao1(float momey)
    {
        Console.WriteLine("中介一需要:"+momey+"$");
    }
    public void zhao2(float momey)
    {
        Console.WriteLine("中介二需要:"+ momey + "$");
    }
    public void zhao3(float momey)
    {
        Console.WriteLine("中介三需要:"+ momey + "$");
    }
    public void zhao4(float momey)
    {
        Console.WriteLine("中介四需要:"+momey + "$");
    }
}

internal class Program
{
    static void Main(string[] args)
    {
        p1 p = new p1();
        //使用系统委托
        //无参数
        Action action;
        action = p.wcs;
        action();

        //参数
        Action<float> action1;
        action1 = p.zhao1;
        action1 += p.zhao2;
        action1 += p.zhao3;
        action1 += p.zhao4;
        action1(182);
        Console.Read();
    }
}

image.png

2.有返回值系统委托 Func<>

代码eg:

eg:😥

class Hout
{

}
class p1
{
    public string Func1()
    {
        return "有返回值函数无参数:";
    }

    public Hout Func2(string name)
    {
        Console.WriteLine("有返回值函数有参数:"+name);
        return null;
    }

}

internal class Program
{
    static void Main(string[] args)
    {
        p1 p = new p1();

        Func<string> func;

        func = p.Func1;

        Console.WriteLine(func());


        Func<string,Hout> func1;

        func1 = p.Func2;

        Hout a= func1("先生");

        Console.Read();
    }
}

image.png

2.3委托之匿名函数

代码eg:

eg:😥

class p1
{
    public Action<string> action;
    public string name;
    public int age;

    public p1(string name, int age)
    {
        this.name = name;
        this.age = age;
    }

    public void isAction(string age)
    {
        Console.WriteLine("我是个中介:"+ age);
        if (action != null)
        {
            action(age);
            Console.WriteLine("我是个中介:" + age);
        }
    }
}

internal class Program
{
    static void Main(string[] args)
    {
        p1 p = new p1("先生",18);

        p.action = delegate (string a)
        {
            Console.WriteLine(a);
            Console.WriteLine("我好蒙啊2");
        };
        p.action += read;

        p.isAction("我好蒙啊1");

        Console.Read();
    }
    public static void read(string name)
    {
        Console.WriteLine(name);
        Console.BackgroundColor = ConsoleColor.Red;
        Console.ForegroundColor = ConsoleColor.Black;
    }
}

❌❌❌如何使用VS进行程序调试


程序是从Main函数开始,顺序执行的

调试就是在你觉得可能会发生问题的地方打下断点

什么是断点?

让程序执行到这个地方暂停下来的点

有什么好处,可以一句句或一段段让程序执行

调试步骤

给想要暂停的代码行添加断点

开始调试

通过监视或局部变量窗口,去看此时你想观察的变量的值

如果想看变量or对象的内存地址

找到即时窗口

&变量名

13.png

总结