Unity面试题

执行环境

运行库执行环境 —-> .NET Framework的核心

公共语言运行库(Common Language Runtime) 简称 CLR

CLR作用:

  1. 微软所有的.NET产品都是由CLR提供运行环境
  2. CLR上运行的语言是一种以字节码形态存在的微软中间语言(MSLIL或IL)所以所有能运行于CLR之上的语言都是可以编译成特定的中间语言
  3. CLR并不是智能运行于Windows也可以运行于其他平台比如移动平台这也是.NET语言可以很方便实现跨平台的原因

不同的语言有不同的编译器,编译器存在的目的是为了审查编程语言的语法是否正确

不同的语言因为有很多的特性差异 语法 和 运行机制都不一定相同

CLR提供了一个同意的平台 屏蔽了不同语言之间的差异性

因为不同语言都被编译成了IL这个中间语言 而CLR只识别IL 不会理会IL是那种语言编译而来

语言支持:

基于CLR的编译器开发的语言

  1. 微软开发: C# VB Phython Ruby F# IL
  2. 其他机构: Lua LOGO PHP

CLR提供的功能

  1. 基类库支持 (比如System.Socket)
  2. 内存管理
  3. 垃圾回收
  4. 线程管理
  5. 安全性
  6. 类型检查
  7. 异常处理
  8. 即时编译(JIT编译器 动态编译 在程序运行时才编译代码 将一条IL语句 编译成机器语言的过程 运行钱编译AOT编译器)

C#编译流程

  1. 把源代码文件 用对应的编译器检查语法和进行源代码分析
  2. 检查分析通过 生成托管模块(PE32 或 PE32 + 文件)
    • 托管模块
      • 中间语言IL :编译C#源代码生成的中间语言代码
      • 元数据:也称元数据表 主要信息时源代码中定义的类型和成员 和 源代码中引用的类型和成员
  3. 将生成的托管模块合并成程序集(Assembly)
    • 文件类型:.dll文件 .exe文件
    • 程序集时一个或多个托管模块的集合 以及 一些资源文件的逻辑组合
    • 程序集必须依靠CLR才能运行 也是 .NET Framework编程的基础组成部分
  4. 执行程序集代码
    • 程序集中包含IL和数据JIT编译器将IL转换成本机CPU可以理解的二进制指令

IOS平台自身的限制问题 不能执行JIT

所以只能通过AOT静态编译器在运行前就编译成目标代码

IOS项目在Windows环境下不能直接打包的原因 必须使用Max XCode进行打包

JIT编译器在编译泛型时的特殊处理

根据类型参数为值或者引用类型分为两种实现

CLR就会被int类型生成一个该方法的int专用模板 仅第一次调用时生成

当下次再次调用泛型方法且参数为int类型 那么就直接使用之前生成好的模板即可(一次创建多次使用)

如果下次传入的类型参数时其他值类型(float doublue struct等)CLR都会在其第一次调用时创建模板

如果是引用类型:

CLR的引用类型参数只用一个通用模板即可 通用模板以object作为类型参数

无论后续传递何种引用 类型参数 只需要做一次替换即可

在泛型的编译器IL部分都只是声明,真正的类型实力化阶段是在CLR的JIT编译阶段实现的 — 晚绑定

面试题

  1. C#的匿名类型,匿名对象,匿名函数分别出现在哪些情景?
    • 匿名函数一般用于回调,只在某个特定情况才会调用的函数
    • 匿名函数创建对象后直接添加到其他引用中,比如添加到list dictionary的情况
    • 匿名类型Linq语句System.Linq
  2. 简述XLua的几种映射方式
    • 映射LuaFunction 或 LuaTable
    • 映射Struct Class Interface
    • 映射到委托
  3. 正向渲染路径细节的原理
    • 三种光照着色:顶点着色 片元着色 球面调和
    • 重要光源使用逐片元光照 次要光源使用逐顶点着色 其他光源使用球面调和计算
    • 逐片元光照在片元着色器中实现,逐顶点光照在顶点着色器中实现,逐片元光照效果要好于逐顶点光照
    • 一个Shader两个Pass一个BasePass一个AdditionalPass 每一个逐像素光源会执行一次Pass
  4. 写出漫反射的计算公式
    • saturate(dot(Normal, LightDir)) * _LightColor0 * DiffuseColor
    • 用世界法线和光照方向做点乘 得到漫反射系数
    • 使用乘法混合实现明暗渐变 漫反射颜色混合光照颜色乘系数
  5. 简述Shader三种测色的区别
    • Shader的逐片元操作时会进行透明度测试 模板测试 深度测试
    • 三者都是用来计算片元是否可以见的
    • 区别在于 透明度测试根据透明阈值进行判断 深度测试根据前后距离进行判断 模板测试是自定义的判断
  6. JIT和AOT的区别
    • JIT 运行时 动态 即时
    • AOT 运行前 静态 非既时
    • 二者都是用来把程序集中的代码编译成机器代码 二进制指令
    • 区别 JIT是在运行时,边编译边运行
    • AOT是运行前提前编译好再去运行
  7. 常规容器和泛型容器有何区别
    • C#常规容器 ArrayList HashTable 等存储类型为object类型的容器
    • 泛型容器是在常规容器基础上扩展而来的泛型容器,存储类型并非object类型
    • 二者都是动态的,不定长度的容器用来存储开发过程中的对象
    • 区别在常规容器如果存储的是值类型,会涉及到拆装箱效率不高
    • 泛型容器杜绝这一情况,使得无论什么类型,都提升了操作效率,杜绝了拆装箱
    • 所以一般情况下开发过程中使用泛型容器情况更多一些
  8. 对泛型有什么认识/理解?
    • 泛型是在声明类型时不明确类型 而是使用占位符 在实际运行时确定类型 也就是延迟绑定,在运行时,JIT编译器会根据时值类型还是引用类型,来生成不同的值类型模板或object模板
    • 泛型的常用情况可以用于泛型方法,泛型类和泛型集合
    • 既可以约束存储对象类型,提高数据的安全性
    • 也可以杜绝拆装箱情况,提升运行效率,优化内存
  9. C#反射的作用
    • 反射是C#的高级语法 用来运行时实时获取元数据信息
    • 可以在运行期间动态获取程序集或者类或者方法等程序元素
    • 从而使用这些信息实例化对象,调用方法,属性赋值等一系列操作
    • 在无法明确操作类型时,或者在做一些工具,第三方插件时可以使用反射,更好的提升复用性
    • 但是反射执行效率不高,因为程序集中如果有大量的数据,反射需要执行大量的运算
  10. 如何实现UI界面的多屏幕适配
    • 通过Canvas提供缩放机制一般是基于高度进行缩放
    • 默认开发时要求UI缩放最好时等比,否者会造成UI界面拉伸
    • 如果等比缩放出现黑边,可以使用背景挡板来进行限制
    • 基本保证UI显示完整,不要影响原图的分辨率比例
    • 如果需要控件固定在某一个位置或者屏幕角显示,也可以配合锚点来进行操作
  11. Shader中的副切线如何获取
    • 法线 点乘 切线 = 副切线
  12. 值类型和引用类型的区别
    • 值类型是不继承于object跟父类的数据类型 比如 Int float 或 其他 struct
    • 引用类型特指哪些继承于object根父类的数据类型 比如 string list 等 class
    • 二者都是数据类型 用来存储变量 修改变量 用于运算
    • 区别在于 值类型一般存储较小的生命周期较短的类型 引用类型存储较大的生命周期较长的类型
    • 值类型存储在栈中,引用类型存储在堆中
    • 值类型速度更快,引用类型速度慢
    • 值类型数据在作用域结束后自动销毁,引用类型数据的释放有延迟,要等待GC回收
  13. 面向对象三大特征
    • 面向对象三大特征分别是:封装 继承 和 多态
    • 首页封装主要体现在函数封装,类的封装,以及在类中的private public protected 等访问权限的限制
    • 继承是多态的前提,用一个父类提供的功能复用给其他的子类,比如属性或方法,减少代码量,提升复用率,但是会增加耦合
    • 多态是面向对象最终的目的,有静态多态和动态多态
    • 静态多态主要靠方法重载来实现是编译器多态
    • 动态多态是靠子类重写父类的虚方法或者纯虚方法来实现,是运行期多态
  14. 内存中的静态区域和动态区域的特点
    • 静态变量是属于整个类的和对象无关,每个对象获取数据是一样,生命周期是最长的,存储在静态区域
    • 实例变量是属于类的对象的,每个对象的数据是对立的不一样的,生命周期和对象的生命周期一致,存储在动态区域
    • 静态区域的数据一般是在运行阶段不会被释放的数据,而动态区域是在运行时会经常变懂,释放的数据
    • static修饰的变量在静态区,其他变量在动态
  15. 简单描述MVC设计模式的思想
    • MVC是指将数据显示逻辑分离的代码框架
    • 三者相辅相成,数据层存储变量,显示层负责所有显示的逻辑,控制层负责所有和现实无关的逻辑
    • MVC框架可以有效得将代码逻辑分离,提升代码得可阅读性,可维护性,解耦合
    • 遵循得是代码设计思想中的单一职责原则
  16. 如何理解C#的属性(访问器)
    • 属性本质是一种方法或者说是一种特殊的方法
    • 一般内部包含get 和 set 两种分程序结构
    • get用于返回数据,set用于给数据赋值
    • 如果一个属性只有get,那么这个属性操作的字段是只读
    • 如果一个属性只有set,那么这个属性操作的字段是只写
    • 如果 set 和 get 同时存在,说明此变量是可读可写
  17. 如何控制A类物体一定比B类物体的前面渲染
    • A的Shader的渲染队列小于B的Shader的渲染队列
    • 或使用深度测试,模板测试实现
  18. Unity动态加载资源的方式有几种?什么区别?
    • Resources 资源来自于磁盘 项目目录 Load 将磁盘中的资源加载的缓存,同步操作 并在之后用于实例化,项目打包是Resources比必定打包
    • AssetBundle资源来自于磁盘也可以来自于远端,一般会经历DownLoad 和 Load 两个过程 项目打包时 AssetBundle资源无需打包
    • 项目中常用的无需经常迭代的资源,都可以使用Resources其他资源可以通过AssetBundle来打包下载,可以节省项目包的大小
  19. 在类的构造函数前加上Static会报什么错?为什么?
    • 静态构造不允许访问修饰符,也不允许参数
    • 无论创建多少类型的对象,静态构造只调用一次
    • 类实例化或者首个静态成员调用之前,静态构造函数先调用
    • 优先级高于其他任何构造函数
    • 内部也无法使用this base的关键字
  20. 简述什么是二分查找
    • 首先表中元素必须是升序排列,将表中间位置元素与查找字比较
    • 如果相等则查找成功,否则根据中间位置划分出两个前后子表
    • 如果大于查找关键字,则进一步查找前子表,否者进一步查找后子表
    • 直到找到满足条件的记录,则查找成功
    • 或子表不存在为止,则查找失败
  21. Shader如何实现半透明效果
    • 确保开启了透明混合,然后渲染队列设置在3000之后
    • 通过调整片元着色器的返回值Fixed4的alpha设置小于1的结果就是半透明
  22. 面向对象和面向过程的区别及其优缺点?
    • 面向过程是分析出解决问题的步骤,然后一步步实现,使用时分布调用即可
    • 面向对象是把问题分解成各个对象,建立对象的目的不是为了完成一个步骤,而是描述解决问题的行为
    • 面向过程:优点 性能高
      • 缺点:复用性不高 扩展性不高 不易维护
    • 面向对象:有点易维护 易复用 易扩展 设计出 低耦合的系统,更加灵活
      • 缺点:性能低 类的调用都需要实例化 开销大 耗资源

上一篇
下一篇