Administrator
发布于 2024-10-15 / 12 阅读
0
0

大世界引擎C#基础

详细语法这点见OO,我必须知道的C#我必须知道的C# - yeyuotc

这里简单陈述

继承

复用父类让子类的代码更简洁,专注于子类扩展自己的东西

//继承: 复用,隐藏,扩展

//复用,父类声明隐藏子类,扩展子类,不用每次都改父类

//覆写 父类中virtual和子类中override

//不想扩展可以使用 sealed

//使用: 复用类很多东西都适用把公共的代码提取出来

//想要类更适配就把基类写成泛型类

//模板配合泛型也是继承

// 接口继承与类的继承区别

// 继承有子类继承父类的关系在,属于IS-A的关系,狗是一种动物,属于的关系

// 接口是包含关系,不能说狗包含动物,什么时候是?我有一个手/我有一个头是包含关系

// 左手和右手就是接口的一个类

// 不能继承两个类的原因,一个类是有界门纲目科属种的

//不能一次同时属于两个类,这是禁止的,但是接口可以

//接口可以像是unity的组件,可以通过不同的接口组成不同的类

//对类可以通过 is来判断有没有这个接口,动态的判断有没有接口

//面向接口编程,面向的是抽象接口,IHand可以是左右手是一个具体的,但我们并不需要

// abstract 很严格的定义,所以函数必须不能实现

//子类中必须实现,很抽象的,一个类只定义方法

//没办法直接创建实例

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
#region  //继承
//继承: 复用,隐藏,扩展
//复用,父类声明隐藏子类,扩展子类,不用每次都改父类
//覆写 父类中virtual和子类中override
//不想扩展可以使用 sealed 
//使用: 复用类很多东西都适用把公共的代码提取出来
//想要类更适配就把基类写成泛型类
//模板配合泛型也是继承
class ParentClass
{
    string name; //父类钟定义的方法和属性
    virtual public void Do() { } //密封时候不可以使用virtual
}
//基类
class ChildClass : ParentClass
{
    //子类钟新定义的方法和属性,把前面的父类直接复用过来
    override public void Do() { }
}
class Example
{
    void example()
    {
        ChildClass child = new ChildClass(); //按人眼,前面是一个child 后面也是child 就可以用到child的东西
        ParentClass parent = new ChildClass();//按人眼,前面是一个parent,对我们来说是一个parent但不知道指向的是一个child
    }
    //隐藏的效果
    void File1()
    {
        ParentClass parent = new ChildClass();
    }
    void File2()
    {
        ParentClass parent; //对于第二个文件来说并不知道指向Childclass
        //不需要知道child
    }
}


#endregion
// 接口继承与类的继承区别
// 继承有子类继承父类的关系在,属于IS-A的关系,狗是一种动物,属于的关系
// 接口是包含关系,不能说狗包含动物,什么时候是?我有一个手/我有一个头是包含关系
// 左手和右手就是接口的一个类
interface IHand{}

interface Ileg { }
class LeftHand : IHand { } //这里是扩展

//不这样 class Man:LeftHand{}
//而是这样:
class Man : IHand //但是人和手是包含的关系,就是表示的关系不同C#做了区别
{}
class A { };
class B { };
// 不能继承两个类的原因,一个类是有界门纲目科属种的
//不能一次同时属于两个类,这是禁止的,但是接口可以
//接口可以像是unity的组件,可以通过不同的接口组成不同的类
//对类可以通过 is来判断有没有这个接口,动态的判断有没有接口
//面向接口编程,面向的是抽象接口,IHand可以是左右手是一个具体的,但我们并不需要
class C : A //, B
{
    bool Is_haveinterface()
    {
        Man man = new Man();
        return (man is IHand);
    }
}
// abstract 很严格的定义,所以函数必须不能实现
//子类中必须实现,很抽象的,一个类只定义方法
//没办法直接创建实例

C#类型系统

类型系统

//Type

//变量的大小,储存的布局,执行的操作都是由类型决定

// int +/- char struct(复杂)

//定义了规则,使用类型系统/操作系统一样,内置在编程语言中提供规则

//怎么获取数据类型?

C#是一个 编译期的语言,静态语言,很多信息在编译时知道

一个变量的类型在编译时知道

由类型系统进行编码,把int放入操作系统

通用类型(generic type)

var,object,dynamic,template

强类型,静态类型:在编译时候已经知道他是一个什么样的类了

强绑定 var,object是强类型,虽然什么类型都能赋值给它,但是在编译时就知道

object 万能类型,也可以被后面的类型传过去,相当于把被赋值对象的值类型抹去了

泛型也叫模板 template

我这类就写一次,通过传入不同类型的参数来生成其它的类,但是这个类的代码和原来的一样

想想jiangly的线段树模板,不同的签名,仍是静态类型,在编译期确定

dynamic是动态类型

只有当代码执行到这里才知道这里的类型,运行时确定

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

//类型系统
//Type
//变量的大小,储存的布局,执行的操作都是由类型决定
// int +/- char struct(复杂)
//定义了规则,使用类型系统/操作系统一样,内置在编程语言中提供规则
//怎么获取数据类型?
/*
 C#是一个 编译期的语言,静态语言,很多信息在编译时知道
一个变量的类型在编译时知道
由类型系统进行编码,把int放入操作系统
 */
/*
  通用类型(generic type) 
    var,object,dynamic,template
  强类型,静态类型:在编译时候已经知道他是一个什么样的类了
  强绑定 ,var,object是强类型,虽然什么类型都能赋值给它,但是在编译时就知道
  object 万能类型,也可以被后面的类型传过去,相当于把被赋值对象的值类型抹去了
  泛型也叫模板 template
  我这类就写一次,通过传入不同类型的参数来生成其它的类,但是这个类的代码和原来的一样
  想想jiangly的线段树模板,不同的签名,仍是静态类型,在编译期确定
    dynamic是动态类型
  只有当代码执行到这里才知道这里的类型,运行时确定
 */

class Animal<T> //任意的类型,吃不同类型的生物应该是不同的生物,复用不同代码
{
    T food;
}
class Example2
{
    void example()
    {
        int a = 1;
        Type type=a.GetType();//类型本身也可以当变量来用,两个操作互补
        int b=(int)Activator.CreateInstance(type);//用法用类型创建一个实例
        //大量使用通用类型,只能通过实时的获取类型的信息才知道
        var v = a;
        object o = new string("string");
        Animal<int> a1 = new Animal<int>(); //在编译会找到这个类型把上面代码复制一份,并把泛型替换
        Animal<float> b1 = new Animal<float>();
        dynamic myvalue = 42; //只有当代码执行到这里才知道这里的类型,运行时确定
    }
}

委托

委托

//封装:封装的函数对象,被调用的地址,甚至被调用的函数,调用者都可以封装成object

//解耦合

delegate,Action

多播

Func

//不同代码的耦合严重,各种数据乱飞,可读/维护/扩展难度大

//设计模式,技术来解决

* 封装

点外卖,打电话来点,每天都吃不一样,要记住每个店的电话

现在在软件上点,不需要知道电话是多少,做了封装把电话隐藏起来了

软件就作为了一个媒介

解耦

轮询/问有空 和 他什么时候有空主动回复你

这样可以两个并行的做事

除了delegate还有Action,也可以用匿名函数,在没有class时

Func是C#定义的模板类一个输入,一个输出,参数个数可以很多

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
/*
    委托 
      //封装:封装的函数对象,被调用的地址,甚至被调用的函数,调用者都可以封装成object
      //解耦合
	关键字:
    delegate,Action
    多播
    Func
 */
//不同代码的耦合严重,各种数据乱飞,可读/维护/扩展难度大
//设计模式,技术来解决
/*
 * 封装
    点外卖,打电话来点,每天都吃不一样,要记住每个店的电话
    现在在软件上点,不需要知道电话是多少,做了封装把电话隐藏起来了
    软件就作为了一个媒介
   解耦
     轮询/问有空 和 他什么时候有空主动回复你
    这样可以两个并行的做事
 */
/*
   除了delegate还有Action,也可以用匿名函数,在没有class时
    Func是C#定义的模板类一个输入,一个输出,参数个数可以很多
 */
public class Me{
    /*
    public delegate void PhoneCall(int product,int cnt); //定义封装的函数长什么样子
    //参数可以扩展,定义返回值和参数
    public event PhoneCall phoneCallEvent;  //创建了一个这样的实例
    */
    public Action<int,int> phoneCallEvent; //返回值为空与上面两行一样,更方便一点
    public void GoToEat(int product)
    {
        phoneCallEvent?.Invoke(product,1);
    }
}
public class Shop
{
    public void Cook(int product,int cnt) //需要上下形参一样
    { }
    //下单以后也要通知我,给他一个委托,作完通过委托通知我
    //委托作为参数,用函数类来封装,来实现类与类的解耦
    public void Order(Func<int,int> order)
    {
        order(1);
    }
}
public class Shop2
{
   public void Cook(int product, int cnt) //需要上下形参一样
    {
    }
}
public class ExampleDelegate : MonoBehaviour
{
    void Start()
    {
        Me me = new Me();
        Shop shop = new Shop();
        Shop2 shop2 = new Shop2(); 
        me.phoneCallEvent += shop.Cook; //注册,把app信息注册到事件里
        me.phoneCallEvent += shop2.Cook; //多播一下点两个外卖,再次传参数会一下调用两个
        me.phoneCallEvent += (int a, int b) => { }; //两个函数,参数/内容
        me.GoToEat(10); //我要吃第10号外卖,会调到下面一个事件 shop里的cook
        shop.Order((int a) => { return a + 1; }); //这样也是委托的实现方法,委托作为参数
    }

}

C# 反射

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using System.Reflection; //加上反射的命名空间

//反射:https://blog.csdn.net/weixin_45136016/article/details/139095147
/*想在代码运行时查看某些信息,并切操作数据
 可以看到程序的细节,想要知道黑盒内部就要拆开查看
关键字:
  Filed
  Attribute是一个属性 可以标记类/方法/变量,在之前标记后编译时会生成源数据
  自定义Attribute可以扩展 HBO,继承表然后再加新的变量
*/
class LEIgfhne
{
    [Bind("yeyuotc")] public int a; 
}
class Bind : Attribute
{
    string name;
    public Bind(string name)
    {
        this.name = name;
    }
    //这里改了上面的特性也要加入传递信息,相当于打标签,需要额外的信息,机票的概念

}
public class ExampleReflection : MonoBehaviour
{

    //默认私有的话在编译器里看不见
    //public 就可以,但想让私有又在编译器里看就用 SerializeField
    void Start()
    {
        LEIgfhne waffw = new LEIgfhne();
        //从变量里知道:这个类里有多少成员变量
        var fileds=waffw.GetType().GetFields(System.Reflection.BindingFlags.Public|System.Reflection.BindingFlags.NonPublic);
        for(int i = 0; i < fileds.Length; i++)
        {
            FieldInfo field = fileds[i];
            Bind b=Attribute.GetCustomAttribute(field, typeof(Bind)) as Bind;
            if (b != null)
            {
                //B不为空就说明这个域可以拿出来这样一个Bind
                Debug.Log("------yzh-----");
            }
        }
        int aa = 0;
    }

}

Linq

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using System.Reflection;
using System.Linq;
//LINQ (Language Intergrated Query)
/*
    数据查询语言,对数据进行查询的库, 数组/XML
    此外还有第一个数/最后一个数/统计数量/求总和等等
    像一个求平方和的操作
    int numbers[]={1,2,3,4,5}
    int squares[5];
    for(int i=0;i<5;i++) squares[i]=numbers[i]*numbers[i];
    更加优雅的方法
 */
public class ExampleReflection : MonoBehaviour
{
    void Start()
    {
        List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };
        int [] squares=numbers.Select(x => x * x).ToArray(); //这是一个lamba表达式求平方
        //求完后再转ToArray,更高级的抽象/封装,可读性高很多
        //想要判断有没有数字大于x,c++就要for循环但C#可以用any里面用lamda表达式,可以用函数封装起来
        bool s=numbers.Any(x => { return x > 3; });
        if (s)
        {
            //判断完再用where找再ToArray就行
           int [] sss=numbers.Where(x => x > 3).ToArray();
        }

    }

}


评论