乱七八糟的一些知识点

本文介绍了C#中的二进制表示、类型区别、异或运算、集合遍历等基础知识,并探讨了接口与抽象类的不同之处及如何优化Unity中的DrawCall。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

记点乱七八糟的东西,免得自己忘了查起来麻烦

 

负数二进制

~0 = ~00000000 = (取反)11111111 = (-1)11111110 = (反码)10000001 = -1

负数即,二进制的第一位数代表符号位,0为正数,1为负数。

负数的反码,即符号位不动,其余取反。-5 = 10000101 = (反码)11111010

负数的补码,即反码+1。-5 = (反码)11111010 = (补码)11111011

系统中负数的二进制存的是补码,如:

int x = -17;

string str= Convert.ToString(x,2);
Debug.Log(str);

输出结果:

11111111111111111111111111101111

 

IEnumerable和IEnumerator

c#中,当一个类继承IEnumerable接口,或者类中实现IEnumerator GetEnumerator()方法,这个类即可使用foreach去遍历。

详情请见:https://docs.microsoft.com/zh-cn/dotnet/api/system.collections.ienumerator?view=netframework-4.7.2

using System.Collections;
using UnityEngine;

public class Test : MonoBehaviour{

    void Start(){
        TextEach te = new TextEach(new string[] {"111", "222", "333", "444", "555", "666" });
        foreach(var t in te) {
            Debug.Log("t    "+t);
        }
    }

}

public class TextEach : IEnumerable {

    string[] array;

    public TextEach(string[] arr) {
        array = arr;
    }

    public IEnumerator GetEnumerator() {
        return new TextEachEnum(array);
    }
}

public class TextEachEnum : IEnumerator {

    public string[] array;
    int index = -1;

    public TextEachEnum(string[] arr) {
        array = arr;
    }

    public object Current {
        get {
            return array[index];
        }
    }

    public bool MoveNext() {
        index++;
        return (index < array.Length);
    }

    public void Reset() {
        index = -1;
    }
}

 

异或 ^

1.0^0=0,0^1=1  0异或任何数=任何数

2.1^0=1,1^1=0  1异或任何数-任何数取反

3.任何数异或自己=把自己置0。 a^a = 0,a^b^a = b^0 = b

4.使某些特定的位翻转,例如对数10100001的第2位和第3位翻转,则可以将该数与00000110进行按位异或运算

10100001^00000110 = 10100111

5.两个变量的值交互

例如交换两个整数a=10100001,b=00000110的值。

a = a^b;   //a=10100111    (c = a^b)

b = b^a;   //b=10100001    (b = b^c = b^a^b = a)

a = a^b;   //a=00000110    (a = c^a = a^b^a = b)

6.a = b^c^d => b = a^c^d

 

值类型和引用类型

值类型:

值类型是在栈中分配内存,在声明时初始化才能使用,不能为null。 

值类型超出作用范围系统自动释放内存。 

主要由两类组成:结构,枚举(enum),结构分为以下几类: 

1、整型(Sbyte、Byte、Char、Short、Ushort、Int、Uint、Long、Ulong) 

2、浮点型(Float、Double) 

3、decimal 

4、bool 

5、用户定义的结构(struct) 

引用类型:

引用类型在堆中分配内存,初始化时默认为null。 

引用类型是通过垃圾回收机制进行回收。 

包括类、接口、委托、数组以及内置引用类型object与string。

 

示例

值类型保存在栈中,故等值不等址;引用类型保存在堆中,故等值等址。

struct structA = new struct();
structA.value = 10;
struct structB = structA;
structB.value = 20;
//此时structA.value = 10; structB.value = 20;

class classA = new class();
classA.value = 10;
class classB = classA;
classB.value = 20;
//此时classA.value = 20; classB.value = 20;

String

string是一种特殊的引用类型,首先它可以像值类型一样去赋值

string str1 = "aaaa";

其次string的值是不可改变的。修改其中一个字符串,就会创建一个全新的string对象,而原有的值不会发生任何变化。

string str1 = "aaaa";
string str2 = str1;
//str2 = str1 = "aaaa", 且地址相同

str1 = "bbbb";
//会生成一个新的string "bbbb" 此时str1 = "bbbb", 而str2 = "aaaa"

 

装箱拆箱

概念:

由于C#中所有的数据类型都是由基类System.Object继承而来的,所以值类型和引用类型的值可以通过显式(或隐式)操作相互转换,而这转换过程也就是装箱(boxing)和拆箱(unboxing)过程。而且这个过程是要额外耗费cpu和内存资源的,所以我们要尽量通过重载函数或者泛型GenericList<T>来避免。

装箱:

是值类型到 object 类型或到此值类型所实现的任何接口类型的隐式转换。对值类型装箱会在堆中分配一个对象实例,并将该值复制到新的对象中。

例如有方法为public SetValue(Object obj);调用的时候传入参数为值类型,SetValue(1);这个时候就会进行装箱操作。

拆箱:

是从 object 类型到值类型或从接口类型到实现该接口的值类型的显式转换。

例如 int x = (int)obj;

 

接口和抽象类的区别:

  1. 抽象类可以有构造方法,接口中不能有构造方法;
  2. 一个类可以实现多个接口,但只能继承一个抽象类;
  3. 抽象类可以包含静态方法,接口中不能包含静态方法
  4. 接口不能包含字段,抽象类可以有字段。
  5. 实现接口的时候必须要实现接口中的所有的方法,不能遗漏任何一个。
  6. 子类必须override抽象类中的所有抽象属性和抽象方法,如果没有全部override,那么子类必须是抽象类
  7. 接口可以用于支持回调,而继承并不具备这个特点
/*
 *抽象类可以但不是必须有抽象属性和抽象方法,但是一旦有了抽象方法,就一定要把这个类声明为抽象类
 * */
public abstract class AbstractClass {
    //私有字段
    private int m_x;
    //公有属性
    public int x { get { return m_x; } }

    //公有字段
    public int y;
    //抽象属性(必须是公有的)
    public abstract int sum { get; }

    //构造方法
    public AbstractClass() {
        m_x = 10;
        y = 5;
    }

    //抽象方法(必须是公有的)
    public abstract int Add();
}

/*
 * 接口的成员包括方法、属性、索引器、事件
 * 接口中不能包含常量、字段(域)、构造函数、析构函数、静态成员
 * 接口中的所有成员默认为public,因此接口中不能有private修饰符
 * */
public delegate void Callback();
public interface Interface {
    //属性
    string s { set; get; }
    //方法
    void LogS();
    event Callback cb;
}

public class Test : AbstractClass, Interface {
    //抽象类的实现
    public override int sum {
        get {
            return Add();
        }
    }
    public override int Add() {
        return x + y;
    }

    //接口的实现
    public string s {
        get {
            return s;
        }

        set {
            s = value;
        }
    }
    public void LogS() {
        
    }
    public event Callback cb;
}

ref/out

//ref前必须先赋值
int a = 0;
RefMethod(ref a);

int b;
OutMethod(out b);


public void RefMethod(ref int a) {
}

public void OutMethod(out int b) {
    //方法内必须赋值
    b = 0;
}

Material与ShareMaterial

Renderer.material

当我们引用修改这个属性的时候,Unity会返回该Render下第一个实例化后的material赋予当前的Rederer组件。即每一次引用就会生成一个新的material到内存中。但是在引用后并不会改变我们项目工程中材质球的原始属性设置。这在销毁物体的时候需要我们手动去销毁该material,否则会一直存在内存中。也可以在场景替换的时候使用Resources.UnloadUnusedAssets去统一释放内存。

即,假设Material M1 为白色,场景中的物体A和B,都使用了M1,此时修改A.material 为黑色的时候,A会变为黑色,B还是白色。

Renderer.sharedMaterial

当我们改变Renderer.sharedMaterial的时候,所有使用这个材质球物体都会被改变,并且改变后的设置将会被保存在项目工程中。并不会生成新的material。

即,假设Material M1 为白色,场景中的物体A和B,都使用了M1,此时修改A.sharedMaterial为黑色的时候,A和B都会变为黑色

 

DrawCall优化

动态批处理

unity自己执行,每一帧把可以进行批处理的模型网格进行合并,再把合并后模型数据传递给GPU,然后使用同一个材质对其渲染。

顶点数太多的物体,无法进行动态批处理,无法减少DC(可以使用静态批处理来减少DC)

不同材质的物体,无法进行动态批处理,无法减少DC

静态批处理

勾选Static(Batching Static),只在运行开始阶段,把需要进行静态批处理的模型合并到一个新的网格中,这意味着这些模型数据不可以在运行时刻被移动。

不同材质的物体,无法通过静态批处理减少DC。但是静态批处理可以通过合并网格来提高性能。

 

具体如:

  1. 减少shader中的pass
  2. shader中少使用顶点属性,或者模型顶点数要尽可能少
  3. 使用相同的材质
  4. 合并网格

 

时间复杂度

常见的算法时间复杂度由小到大依次为:Ο(1)<Ο(log2n)<Ο(n)<Ο(nlog2n)<Ο(n2)<Ο(n3)<…<Ο(2n)<Ο(n!)

 

git仓库 .gitignore规则不生效

.gitignore只能忽略原来没有被追踪的文件(即未提交到仓库的),如果某些文件已经被纳入了版本管理中,则修改.gitignore是无效的。

解决方法就是,我们要先把本地缓存删除(改变成未追踪状态),然后重新提交

git rm -r --cached .
git add .
git commit -m 'update .gitignore'

 

像数组一样,使用下标访问一个类的对象

public class Data
{
    
}

public class DataManager
{
    List<Data> dataList = new List<Data>();

    public Data this[int index]
    {
        get { return dataList[index]; }
    }
}

//使用
DataManager manager = new DataManager();
Data data = manager[0];

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值