VR引擎开发0202

118 阅读14分钟

复习,外加里氏转换等一小部分补充内容

创建父类

    class Person
    {
        public Person(string name)
        {
            this.Name = name;
        }
        public string Name;//默认空字符串
        public int num;//默认0
        public virtual void SayHello() //virtual,虚函数,允许重写
        {
            Console.WriteLine("hello"+Name);
        }
        public new void Iam()//隐藏函数
        {
            Console.WriteLine("我是父类");
        }

    }

创建子类

   class Student : Person
    {
        public Student(string name, int id) : base(name)
        {
            this.id = id;
        }
        public int id;

        public override void SayHello()
        //对函数的重写(虚函数)隐藏函数,调用子类的同名方法,将父亲的同名函数隐藏。
        {
         //   base.SayHello(); //调用父类的方法,可能我们还会用到父类中的函数体
         Console.Write("hello");
        }
        public  void Iam()//隐藏函数
        {
            Console.WriteLine("我是子类");
        }
        public void getNum()
        {
            Console.WriteLine("111");
        }
    }

测试

            //所有的类都有一个基类 Object,拥有共同的一些方法
            Person person = new Person("xiaoming");
            Console.WriteLine(person.Name);
            Student student = new Student("xiaohua", 12);
            student.SayHello();
            Person personStudent = new Student("xiaonam", 123);//Person类型的
            personStudent.SayHello();
            //personStudent.getNum();Person 类型,只能使用Person中的一些方法和属性
            student.getNum();
            Person student2 = (Person)student;
            //里氏转换 子类实例化对象可以定义为父类类型,也可以强转为父类类型。
            student.Iam();
            personStudent.Iam();

抽象类

抽象一个父类,告诉你子类必须要实现的内容,抽象类不能实例化对象,只能被继承

定义一个抽象类

        public abstract class MyMath //抽象类因为不完整,不能实例化
        {
            public int num;
            public int Max()
            {
                return 1;
            }
            public abstract int Min();//表示这个方法还没实现
            public abstract int getMult();//表示这个方法还没实现

        }

继承这个抽象类

       public class Number : MyMath //子类继承的时候,要实现所有抽象方法
        {
            public override int getMult()
            {
                return 2;
            }

            public override int Min()//对父类中的min方法进行实现
            {
                return 0;

            }
        }

c#权限定义

        public 最高权限,在其他项目也可以访问
        private 私有的,只能在定义的类中使用,派生类也不行
        protected 被保护的, 在类和派生类中使用
        internal 只能在同一个项目中使用

密封类

如果这个类不想被继承 sealed

         public sealed class MyTest
        {
            public void Test()
            {
                Console.WriteLine("测试");
            }
        }
        //class Yourtest : MyTest { } 密封类无法被继承

static 静态和实例成员(非静态)的区别

  • 被static修饰的是静态成员,没有被static修饰的是非静态成员(实例成员)
  • 在非静态类中可以有静态成员,也可以有非静态成员,但是静态类中只能有静态成员
  • 在类中,静态方法要调用的话只能通过类名.方法名,不能通过对象名.方法名调用

创建一个静态类 相当于是一个工具类

        public static class Bhavior// 静态类中只能有静态成员,静态类不能实例化成对象
        {
           // public int num;//不能在静态类中生成实例化对象
           public static void talk()
            {
                Console.WriteLine("说话");
            }
        }

静态类不能被继承

class Teacher: Bhavior { }//报错

非静态类 可以有静态成员,也可以有实例成员

        public class Color
        {
            public Color(int num)
            {
                this.num = num;
            }
            public readonly int num; //readonly 只能在声明和构造函数中初始化赋值,在其他地方不能修改其值,只能被读取,不能被修改
            private static int colorNum;

            public void ShowColor()
            {
                Console.WriteLine("red"+num);
            }

            public static void ChangeColor()
            {
            //静态方法只能访问静态成员的数据
            //静态成员不是给对象使用的
                //Console.WriteLine(num); 无法访问非静态的变量
                Console.WriteLine("blue"+ colorNum);
            }
        }

readonly

只能在声明和构造函数中初始化赋值,在其他地方不能修改其值,只能被读取,不能被修改

image.png


image.png 创建类Circle ,包含常量pi 静态方法周长,静态方法面积,非静态方法体积

输入半径,输出周长,面积,体积

       public class Circle
        {
            public Circle(int r )
            {
               Circle.r = r;//静态字段要访问只能通过类名.字段名
            }
            public static int r;
            public const double pi = 3.14; //const 定义常量
            public static double GetPerimeter()
            {
                return pi * r * r;
            }
            public static double GetArea()
            {
                return 2 * pi * r;
            }
            public double GetVolume()
            {
                return (4.0 / 3) * pi * r * r * r;
            }
        }

实例化测试

            Circle circle = new Circle(5);//半径为5
            Console.WriteLine(circle.GetVolume() +" "+ Circle.GetArea()+ " " + Circle.GetPerimeter());
            //静态字段要访问只能通过类名.字段名

接口

接口相当于是一个规范,接口可以实现多继承,接口指定一组没有函数体的函数成员,也就是说只提供了一些没有函数体的函数,具体怎么实现还要我们在自己的类中去实现。

  • 接口中包含很多没有实现的函数成员,每个成员不需要设置访问修饰符,默认都是 public公开的
  • 接口中可以放方法,属性(只能用自动属性就是简写模式),索引器,这些的本质其实还是函数
  • 因为接口中的函数都是没有实现的,所以接口是不能实例化的
  • 接口可以被类继承,接口可以多继承其他接口

创建fly和eat的接口

    public interface Fly
    {
        //接口中的函数都不需要修饰符 默认都是公开
        void fly();//没有函数体的函数
        int Speed();
        int high
        {
            set;get;//没有函数体的函数
        }
    }
    //创建一个Eat接口
    public interface Eat 
    {
        void MyEat();
    }

创建“超级接口”来继承eat和fly方法

   public interface SuperInter:Fly,Eat //一个类继承多个接口,一个接口可以继承多个接口

    { 
        public void MyEat()
        {
            Console.WriteLine("chii");
        }
    }

定义一个类

    public class Animal
    {
        public void Walk()
        {
            Console.WriteLine("行走");
        }
    }

可以继承一个类和多个接口

    public class Bird : Animal,Fly,Eat
    {//继承一个类和多个接口时,类要写在最前面
        public int high { get => 17; set => throw new NotImplementedException(); }// "=> 1" 相当于return 1
       // int Fly.high { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }

        public void fly()
        {
            Console.WriteLine("飞");
        }

        public void MyEat()
        {
            Console.WriteLine("类中的吃");
        }
        void Eat.MyEat()// 使用接口名.函数名 调用接口中的函数
        {
            Console.WriteLine("接口中的吃");

        }

        public int Speed()
        {
            Console.WriteLine("速度");
            return 10;
        }
    }

测试

            Bird bird = new Bird();
            Eat bird1 = new Bird();//接口Eat类
            bird.fly(); 
            bird.MyEat();
            bird.Walk();
            bird1.MyEat();//接口中的吃

显示实现接口 我们在开发中如果自己的类中有和接口中同名的函数,那么在继承接口的时候,类中的同名函数会被认为是实现接口中的函数,但是我们就想区分出来,另外去实现接口中的函数怎么办呢?

image.png

File类处理小文件的读写

逐行读取文件中的信息到字符串数组中

            string[] fsRead = File.ReadAllLines("./1.txt", Encoding.UTF8);
            foreach(string fs in fsRead)
            {
                Console.WriteLine(fs);
            }

读取文件中的信息到字符串中

            string fStr = File.ReadAllText("./1.txt");
            Console.WriteLine(fStr);

向文件中写入信息(覆盖形式)

            string fWrite = "\ngoodbye";
            //向文件中写入信息(覆盖形式)
            File.WriteAllText("./1.txt", fWrite);//替换的形式

向文件中写入信息(追加的形式)

            File.AppendAllText("./1.txt", fWrite);//插入的形式,字符串
            File.AppendAllLines ("./1.txt", fsRead);//插入的形式,数组

总结 Text字符串,Lines数组

泛型类

我们很多时候在往方法传参数都是固定某种类型的数据,但是很多时候我们数据类型可能是多种的,比如你比较两个数的大小有可能是小数也有可能是整数(这里只是举例子),那么你要对不同数据类型进行操作就要使用到泛型


定义了一个泛型类,T相当于一个变量,创建对象的时候,就可以规定类型
    public class Dmi<T>
    {
        public Dmi(T weight,T high,string name)
        {
            this.weight = weight;
            this.high = high;   
            this.name = name;
        }

        public T weight;
        public T high;
        public String name;

        public T GetDmi()
        {
            //创建一个动态类型的变量,
            dynamic weight1 = weight;
            dynamic high1 = high;
            return weight1 * high1;
        }
    }

测试

            Dmi<double> dmi = new Dmi<double>(123,"aaa",10.23);
            Console.WriteLine(dmi.GetDmi());

附 c#中的关键字

类型

Void

用作方法的返回类型时,void 关键字指定方法不返回值。

在方法的参数列表中不允许使用 void。采用以下形式声明一个无参数的、不返回值的方法:

Ovid SampleMethod();

Var

在方法范围中声明的变量可以具有隐式类型 var。隐式类型的本地变量是强类型变量(就好像您已经声明该类型一样),但由编译器确定类型。 有返回值

引用类型

Class

类是使用关键字 class 声明的

委托

委托类型的声明与方法签名相似,有一个返回值和任意数目任意类型的参数: 
public delegate void TestDelegate(string message);

public delegate int TestDelegate(MyType m, long num);

delegate 是一种可用于封装命名或匿名方法的引用类型。委托类似于 C++ 中的函数指针;但是,委托是类型安全和可靠的。

接口

接口只包含方法、属性、事件或索引器的签名。成员的实现是在实现接口的类或结构中完成的

Object

object 类型在 .NET Framework 中是 Object 的别名。在 C# 的统一类型系统中,所有类型(预定义类型、用户定义类型、引用类型和值类型)都是直接或间接从 Object 继承的。可以将任何类型的值赋给 object 类型的变量。将值类型的变量转换为对象的过程称为“装箱”。将对象类型的变量转换为值类型的过程称为“取消装箱”。

String

string 类型表示零或更多 Unicode 字符组成的序列。string 是 .NET Framework 中 String 的别名。

尽管 string 是引用类型,但定义相等运算符(== 和 !=)是为了比较 string 对象(而不是引用)的值。这使得对字符串相等性的测试更为直观。

修饰符

Override

要扩展或修改继承的方法、属性、索引器或事件的抽象实现或虚实现,必须使用 override 修饰符。

Virtual

virtual 关键字用于修饰方法、属性、索引器或事件声明,并使它们可以在派生类中被重写。例如,此方法可被任何继承它的类重写。

volatile

volatile 关键字指示一个字段可以由多个同时执行的线程修改。声明为 volatile 的字段不受编译器优化(假定由单个线程访问)的限制。这样可以确保该字段在任何时间呈现的都是最新的值。

unsafe

unsafe 关键字表示不安全上下文,该上下文是任何涉及指针的操作所必需的。

static

使用 static 修饰符声明属于类型本身而不是属于特定对象的静态成员。static 修饰符可用于类、字段、方法、属性、运算符、事件和构造函数,但不能用于索引器、析构函数或类以外的类型。

sealed

当对一个类应用 sealed 修饰符时,此修饰符会阻止其他类从该类继承。在下面的示例中,类 B 从类 A 继承,但是任何类都不能从类 B 继承。

readonly

readonly 关键字是可以在字段上使用的修饰符。当字段声明包括 readonly 修饰符时,该声明引入的字段赋值只能作为声明的一部分出现,或者出现在同一类的构造函数中。

extern

extern 修饰符用于声明在外部实现的方法。extern 修饰符的常见用法是在使用 Interop 服务调入非托管代码时与 DllImport 属性一起使用。在这种情况下,还必须将方法声明为 static

event

event 关键字用于在发行者类中声明事件。

const

const 关键字用于修改字段或局部变量的声明。它指定字段或局部变量的值是常数,不能被修改。

abstract

abstract 修饰符可以和类、方法、属性、索引器及事件一起使用。在类声明中使用 abstract 修饰符以指示某个类只能是其他类的基类。标记为抽象或包含在抽象类中的成员必须通过从抽象类派生的类来实现。

访问修饰符

internal

internal 关键字是类型和类型成员的访问修饰符。只有在同一程序集的文件中,内部类型或成员才是可访问的

private

private 关键字是一个成员访问修饰符。私有访问是允许的最低访问级别。私有成员只有在声明它们的类和结构体中才是可访问的

protected

protected 关键字是一个成员访问修饰符。受保护成员在其所在的类中可由派生类实例访问。

public

public 关键字是类型和类型成员的访问修饰符。公共访问是允许的最高访问级别。

abstract 可以和类、方法、属性、索引器及事件一起使用, 
标识一个可以扩展但不能被实体化的、必须被实现的类或方法。

as 一个转换操作符,如果转换失败,就返回null。

base 用于访问被派生类或构造中的同名成员隐藏的基类成员。

catch 定义一个代码块,在特定类型异常抛出时,执行块内代码。 
参见try和finally。

checked 既是操作符又是语句。 
确保编译器运行时,检查整数类型操作或转换时出现的溢出。

const 标识一个可在编译时计算出来的变量值,即一经指派不可修改的值。

delegate 指定一个声明为一种委托类型。委托把方法封装为可调用实体, 
能在委托实体中调用。

enum 表示一个已命名常量群集的值类型。

event 允许一个类或对象提供通知的成员,他必须是委托类型。

explicit 一个定义用户自定义转换操作符的操作符, 
通常用来将内建类型转换为用户定义类型或反向操作。 
必须再转换时调用显示转换操作符。

extern 标识一个将在外部(通常不是c#语言)实现的方法。

finally 定义一个代码块,在程序控制离开try代码快后执行。参见try和catch。

fixed 在一个代码块执行时,在固定内存位置为一个变量指派一个指针。

foreach 用于遍历一个群集的元素。

goto 一个跳转语句,将程序执行重定向到一个标签语句。

implicit 一个操作符,定义一个用户定义的转换操作符。 
通常用来将预定义类型转换为用户定义类型或反向操作。 
隐式转换操作符必须在转换时使用。

interface 将一个声明指定为接口类型,即实现类或构造必须遵循的合同。

internal 一个访问修饰符。

namespace 定义一个逻辑组的类型和命名空间。

operator 用来声明或多载一个操作符。

out 标识一个参数值会受影响的参数,但在传入方法时, 
该参数无需先初始化。

params 声明一个参数数组。如果使用,必须修改指定的最后一个参数。 
允许可选参数。

readonly 标识一个变量的值在初始化后不可修改。

ref 标识一个参数值可能会受影响的参数。

sealed 防止类型被派生,防止方法和property被覆载。

sizeof 一个操作符,以byte为单位返回一个值类型的长度。

stackalloc 返回在堆上分配的一个内存块的指针。

struct struct是一种值类型,可以声明常量、字段、方法、property、 
索引器、操作符、构造器和内嵌类型。

throw 抛出一个异常。

try 异常处理代码块的组成部分之一。try代码块包括可能会 
抛出异常的代码。参阅catch和finally关键字。

typeof 一个操作符,返回传入参数的类型。

unchecked 禁止溢出检查。

unsafe 标注包含指针操作的代码块、方法或类。

using 当用于命名空间时,using关键字允许访问该命名空间中的类型, 
而无需指定其全名。也用于定义finalization操作的范围。 
virtual 一个方法修饰符,标识可被覆载的方法。

volatile 标识一个可被操作系统、某些硬件设备或并发线程修改的attribute。

一般的构造函数总是public类型的,如果是private类型的,表明类不能被实例化,这通常用于只含有静态的成员的类。

在派生类中声明对虚方法的重载,要求在声明中加上override关键字,而且不能有new,static或virtual修饰符。

密封类在声明中使用sealed修饰符,这样就可以防止该类被其它类继承。