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