一问一答 (C#篇)
值类型与引用类型的区别?
值类型 ValueType
- 数值类型
- 整型
sbyte(System.SByte)
short(System.Int16)
int(System.Int32)
long(System.Int64)
byte(System.Byte)
ushort(System.UInt16)
uint(System.UInt32)
ulong(System.UInt64)
char(System.Char)
- 浮点型
float(System.Single)
double(System.Double)
- 高精度型
decimal(System.Decimal)
- 整型
- 结构体
struct
(直接派生于System.ValueType
)
bool
型bool
(System.Boolean
的别名)
- 用户定义的结构体
- 枚举
enum
(派生于System.Enum
)
- 可空类型
- 派生于
System.Nullable<T>
泛型结构体,T
实际上是System.Nullable<T>
的别名
- 派生于
引用类型(ReferenceType):
- 数组
- 用户定义的类
- 接口
- 委托
- object
- 字符串
- null类型
- 类
- 值类型在栈里, 引用类型故名思意存放的是一个引用地址.
C# 中所有引用类型的基类是什么
- 引用的基类是
System.Object
- 值类型的基类是
System.ValueType
- 值类型也隐式继承自
System.Object
请简述ArrayList
和List<T>
的主要区别
List<T>
是泛型接口,ArrayList
是一个实现了该接口的类, 可以被实例化.ArrayList
存在不安全类型, 因为会把所有插入其中的数据都当中Object
来处理, 同时存在费时的装箱拆箱操作.
简述GC(垃圾回收)产生的原因, 如何避免
new
对象时, 当可分配的内存不足GC就会去回收未使用的对象, 倒是GC的操作时非常复杂的, 会占用很多CPU时间,
对于移动设备来说频繁的垃圾回收会严重影响性能
- 减少
new
对象的次数, 在创建对象时会产生内存碎片, 这样会造成碎片内存不法使用 - 使用公用的对象(静态成员, 常量), 但是不能乱用, 因为静态成员和窗帘的声明周期时整个应用程序
- 在拼接大量字符串的时候使用StringBuilder, 但是在使用的时候注意, 创建StringBuilder对象时要设置StringBuilder的初始大小:
var builder = new StringBuilder(size);
- 使用
object pool
对象池.
描述 Interface
与抽象类abstract
之间的不同
相同点:
- 都可以被继承
- 都不能被实例化
- 都可以包含方法声明
- 派生类必须实现未实现的方法
区别:
抽象类 | 接口 |
---|---|
可以定义字段, 属性, 方法实现 | 只能定义属性, 索引器, 事件, 和方法声明, 不能包含字段. |
一个不完整的类, 需要进一步细化 | 一个行为规范 |
只能单一继承 | 可以被多重实现 |
更多的定义在一系列紧密相关的类之间 | 大多数是关系疏松但都实现某一功能的类中 |
从一系列相关对象中抽象出来的概念, 因此反映的是事物的内部共性 | 为了满足外部调用定义的一个功能约定, 因此反映的是事物的外部特性 |
完全具备继承相关特点 | 不具备继承的任何特点, 它仅仅承诺了能够调用的方法 |
不支持回调 | 支持回调, 因为继承并不具备这个特点 |
具体方法是默认是虚的 | 实现接口的类默认是非虚的, 但也可以声明为虚 |
临时对象
var a = new string("abc"); // 这行会报错
a = (a.ToUpper() + "123").Substring(0, 2);
应该改为:
var a = new string(new[]{'a', 'b', 'c'});
a = (a.ToUpper() + "123").Substring(0, 2);
会产生五个临时变量
遍历删除
var ls = new List<int>(new[] {1, 2, 3, 4, 5});
foreach (var item in ls)
{
Console.WriteLine(item*item);
ls.Remove(item);
}
会产生运行时错误, 不能一遍遍历一遍修改. 可以使用 for
循环来代替, foreach
一般用于读取
关键字 Sealed
如果是类使用的话, 可以防止有其他类继承该类 方法的话则就是防止派生类重写该方法
private
, public
, protected
, internal
的区别
public
: 对任何类和成员都公开, 无限制访问private
: 对该类公开protected
: 对该类和其派生类公开internal
: 只能在包含该类的程序集中访问protected internal
: 包含该类的程序集中且只对该类及其派生类公开
反射的实现原理:
审查元数据并收集关于他的类型信息的能力, 就是得到程序集中的属性和方法
字符串中 null
和 ""
和 string.Empty
的区别?
string.Empty
: 相当于"", Empty
是一个静态只读的字段.
string str = ""
: 初始化对象并且分配一个空字符串的内存空间.
string str = null
: 初始化对象但不会分配内存空间.
从性能和代码生成的角度来看,确实没有什么区别。在性能测试中,他们之间来回跳动,其中一个比另一个快,而且只有毫秒。
在看后面的代码,你真的没有看到任何区别。唯一的区别是在IL
中,它string.Empty
使用操作码ldsfld
而""
使用操作码ldstr
,但这只是因为string.Empty
是静态的,并且两个指令都做同样的事情。如果您查看生产的组件,则完全相同。
C#
private void Test1()
{
string test1 = string.Empty;
string test11 = test1;
}
private void Test2()
{
string test2 = "";
string test22 = test2;
}
IL
.method private hidebysig instance void
Test1() cil managed
{
// Code size 10 (0xa)
.maxstack 1
.locals init ([0] string test1,
[1] string test11)
IL_0000: nop
IL_0001: ldsfld string [mscorlib]System.String::Empty
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: stloc.1
IL_0009: ret
} // end of method Form1::Test1
.method private hidebysig instance void
Test2() cil managed
{
// Code size 10 (0xa)
.maxstack 1
.locals init ([0] string test2,
[1] string test22)
IL_0000: nop
IL_0001: ldstr ""
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: stloc.1
IL_0009: ret
} // end of method Form1::Test2
汇编代码
string test1 = string.Empty;
0000003a mov eax,dword ptr ds:[022A102Ch]
0000003f mov dword ptr [ebp-40h],eax
string test11 = test1;
00000042 mov eax,dword ptr [ebp-40h]
00000045 mov dword ptr [ebp-44h],eax
string test2 = "";
0000003a mov eax,dword ptr ds:[022A202Ch]
00000040 mov dword ptr [ebp-40h],eax
string test22 = test2;
00000043 mov eax,dword ptr [ebp-40h]
00000046 mov dword ptr [ebp-44h],eax
所以"""
与Empty
在用法与性能上基本没区别, 只是后者时语法级别对前者的优化.
在C#中,如何使用string.Empty或String.Empty字符串?
数据大小
byte b = 'a'; // 'a' 是char类型 错误
byte c = 1; // 0~255 正确
byte d = "ab"; // 两个英文 错误
byte e = '啊'; // 中文 错误
byte g = 256; // 0~255 错误
其中byte取值范围在c#中是0~255, java中则是-128~127
以4(100) 7(0111) 8(1000)为例
4 & 3 --> 100 & 011 = 0
7 & 6 --> 0111 & 0110 != 0
8 & 7 --> 1000 & 0111 = 0
即 如果 m & (m - 1) == 0,则m是2的n次方。