31. C#中委托 和 接口有什么区别?各用在什么场合?
接口(interface) 是约束类应该具备的功能集合,约束了类应该具备的功能,使类从千变万化的具体逻辑中解脱出来,便于类的管理和扩展,同时又合理解决了类的单继承问题。
C#中的委托 是约束方法集合的一个类,可以便捷的使用委托对这个方法集合进行操作。
在以下情况中使用接口:
1.无法使用继承的场合
2.完全抽象的场合
3.多人协作的场合
以上等等
在以下情况中使用委托:多用于事件处理中
32. 接口Interface与抽象类
概念
抽象类
当2个或多个类中有重复部分的时候,我们可以抽象出来一个基类,如果希望这个基类不能被实例化,就可以把这个基类设计成抽象类。
当需要为一些类提供公共的实现代码时,应优先考虑抽象类。因为抽象类中的非抽象方法可以被子类继承下来,使实现功能的代码更简单。
接口
当注重代码的扩展性跟可维护性时,应当优先采用接口。
接口与实现它的类之间可以不存在任何层次关系,接口可以实现毫不相关类的相同行为,比抽象类的使用更加方便灵活;
接口只关心对象之间的交互的方法,而不关心对象所对应的具体类。接口是程序之间的一个协议,比抽象类的使用更安全、清晰。一般使用接口的情况更多。
区别
接口不是类(无构造函数和析构函数),不能被实例化,抽象类可以间接实例化(可以被继承,有构造函数,可以实例化子类的同时间接实例化抽象类这个父类)。
接口只能做方法申明,抽象类中可以做方法申明,也可以做方法实现。
抽象类中可以有实现成员,接口只能包含抽象成员。因此接口是完全抽象,抽象类是部分抽象。
抽象类要被子类继承,接口要被类实现。
抽象类中所有的成员修饰符都能使用,接口中的成员都是对外的,所以不需要修饰符修饰。
接口可以实现多继承,抽象类只能实现单继承,一个类只能继承一个类但可以实现多个接口。
抽象方法要被实现,所以不能是静态的,也不能是私有的。
使用情形
使用抽象类是为了代码的复用,而使用接口的动机是为了实现多态性。
抽象类适合用来定义某个领域的固有属性,也就是本质,接口适合用来定义某个领域的扩展功能。
33. 函数中多次使用string的+=处理,会产生大量内存垃圾(垃圾碎片),有什么好的方法可以解决。
通过StringBuilder那进行append,这样可以减少内存垃圾
34. C#和C++的区别?
简单的说:C# 与C++ 比较的话,最重要的特性 就是C# 是一种完全面向对象的语言,而C++ 不 是,另外C# 是基于IL 中间语言
和.NET Framework CLR 的,在可移植性,可维 护性和强壮性都比C++ 有很大的改进。C# 的设 计目标是用来开发快速稳定可扩展的应用程序, 当然也可以通过Interop和Pinvoke 完成一些底层操作
具体对比:
继承:C++支持多继承,C#类只能继承一个基类中的实现但可以实现多个接口。
数组:声明 C# 数组和声明 C++ 数组的语法不同。在 C# 中,“[]”标记出现在数组类型的后面。
数据类型:在C++中bool类可以与整型转换,但C#中bool 类型和其他类型(特别是 int)之间没有转换。long 类型:在 C# 中,long 数据类型为 64 位,而在 C++ 中为 32 位。
struct 类型:在 C# 中,类和结构在语义上不同。struct 是值类型,而 class 是引用类型。
switch 语句:与 C++ 中的 switch 语句不同,C# 不支持从一个 case 标签贯穿到另一个 case 标签。
delegate 类型:委托与 C++ 中的函数指针基本相似,但前者具有类型安全,是安全的。
从派生类调用重写基类成员。 base
使用 new 修饰符显式隐藏继承成员。
重写方法需要父类方法中用virtual声名,子类方法用override 关键字。
预处理器指令用于条件编译。C# 中不使用头文件。 C# 预处理器指令
异常处理:C#中引入了 finally 语句,这是C++没有的。
C# 运算符:C# 支持其他运算符,如 is 和 typeof。它还引入了某些逻辑运算符的不同功能。
static 的使用,static方法只能由类名调用,改变static变量。
在构造基类上替代 C++ 初始化列表的方法。
Main 方法和 C++ 及Java中的 main 函数的声明方式不同,Main而不能用main
方法参数:C# 支持 ref 和 out 参数,这两个参数取代指针通过引用传递参数。
在 C# 中只能在unsafe不安全模式下才使用指针。
在 C# 中以不同的方式执行重载运算符。
字符串:C# 字符串不同于 C++ 字符串。
foreach:C#從VB中引入了foreach关键字使得以循环访问数组和集合。
C# 中没有全局方法和全局变量:方法和变量必须包含在类型声明(如 class 或 struct)中。
C# 中没有头文件和 #include 指令:using 指令用于引用其他未完全限定类型名的命名空间中的类型。
C# 中的局部变量在初始化前不能使用。
析构函数:在 C# 中,不能控制析构函数的调用时间,原因是析构函数由垃圾回收器自动调用。 析构函数
构造函数:与 C++ 类似,如果在 C# 中没有提供类构造函数,则为您自动生成默认构造函数。该默认构造函数将所有字段初始化为它们的默认值。
35. C#引用和C++指针的区别
C#不支持指针,但可以使用Unsafe,不安全模式,CLR不检测
C#可以定义指针的类型、整数型、实数型、struct结构体
C#指针操作符、C#指针定义
使用fixed,可以操作类中的值类型
相同点:都是地址
指针指向一块内存,它的内容是所指内存的地址;而引用则是某块内存的别名。
不同点:
指针是个实体,引用是个别名。
sizeof 引用”得到的是所指向的变量(对象)的大小,而“sizeof 指针”得到的是指针本身的大小;
引用是类型安全的,而指针在不安全模式下
引用不能为空,即不存在对空对象的引用,指针可以为空,指向空对象。
引用必须初始化,指定对哪个对象的引用,指针不需要。
引用初始化后不能改变,指针可以改变所指对象的值。
引用访问对象是直接访问,指针访问对象是间接访问。
引用的大小是所引用对象的大小,指针的大小,是指针本身大小,通常是4字节。
引用没有const,指针有const
引用和指针的+自增运算符意义不同。
引用不需要分配内存空间,指针需要。
36. 反射的实现原理?
可以在加载程序运行时,动态获取和加载程序集,并且可以获取到程序集的信息反射即在运行期动态获取类、对象、方法、对象数据等的一种重要手段。
主要使用的类库:System.Reflection
核心类:
Assembly描述了程序集
Type描述了类这种类型
ConstructorInfo描述了构造函数
MethodInfo描述了所有的方法
FieldInfo描述了类的字段
PropertyInfo描述类的属性
通过以上核心类可在运行时动态获取程序集中的类,并执行类构造产生类对象,动态获取对象的字段或属性值,更可以动态执行类方法和实例方法等。
审查元数据并收集关于它的类型信息的能⼒。
实现步骤:
- 导⼊using System.Reflection;
- Assembly.Load(“程序集”)加载程序集,返回类型是
⼀个Assembly - foreach (Type type in assembly.GetTypes())
{
string t = type.Name;
}
得到程序集中所有类的名称 - Type type = assembly.GetType(“程序集.类名”);获取
当前类的类型 - Activator.CreateInstance(type); 创建此类型实例
- MethodInfo mInfo = type.GetMethod(“⽅法名”);获取
当前⽅法 - mInfo.Invoke(null,⽅法参数);
37. C#中基本类型占用的字节数
类型 字节
bool true/false
byte、char 1字节
char、short 2字节
int,float 4字节
long、double 8字节
38. Mock和Stub有何区别?
Mock与Stub的区别:Mock:关注行为验证。细粒度的 测试,即代码的逻辑,多数情况下用于单元测试。 Stub:关注状态验证。粗粒度的测试,在某个依赖系 统不存在或者还没实现或者难以测试的情况下使用, 例如访问文件系统,数据库连接,远程协议等。
39. 为什么dynamic font 在 unicode环境下优于 staticfont(字符串编码)
Unicode是国际组织制定的可以容纳世界上所有⽂字和符号的字符编码⽅案。
使⽤动态字体时,Unity将不会预先⽣成⼀个与所有字体的字符纹理。
当需要⽀持亚洲语⾔或者较⼤的字体的时候,若使⽤正常纹理,则字体的纹理将⾮常⼤。
40. 简述StringBuilder和String的区别?(字符串处理)
String是字符串常量。StringBuilder是字符串变量,线程不安全。
String类型是个不可变的对象,当每次对String进⾏改变时都需要⽣成⼀个新的String对象,然后将指针指向⼀个新的对象,如果在⼀个循环⾥⾯,不断的改变⼀个对象,就要不断的⽣成新的对象,所以效率很低,建议在不断更改String对象的地⽅不要使⽤String类型。
StringBuilder对象在做字符串连接操作时是在原来的字符串上进⾏修改,改善了性能。这⼀点我们平时使⽤中也许都知道,连接操作频繁的时候,使⽤StringBuilder对象。