基础题一
每次看到你,我都会觉得心里很甜,因为是你,让我觉得世界都变得如此美好。 --zhu
1、C#中堆和栈的区别
栈:由编译器自动分配、释放。在函数体中定义的变量通常在栈上。
堆:一般由程序员分配释放。用new、malloc等分配内存函数分配得到的就是在堆上。
栈:存放在栈中时要管存储顺序,保持着先进后出的原则,他是一片连续的内存域,有系统自动分配和维护;
堆:无序,是不连续的内存域,有用户自己来控制和释放,如果用户自己不释放,当内存达到一定值,通过垃圾回收器(GC)回收。
栈内存无需用户管理,不受GC管理。当栈顶元素使用完立马释放。堆则需要GC清理。
使用引用类型的时候,一般是对指针的操作而非引用类型本身。值类型则操作本身。
2、C#中的委托是什么?事件是不是一种委托
委托本质是一个类,委托是将一种方法作为参数代入到另一个方法。委托允许你将方法作为参数传递给其他方法,或者将方法作为回调方法存储在委托变量中。
public delegate void MyDelegate(string message);
事件(Event)是基于委托的一种特殊用法,它用于实现发布-订阅模式。事件允许对象向多个订阅者通知其状态的改变。事件本质上是一个具有特定签名的多播委托。当事件发生时,所有订阅了该事件的方法都会被调用。
public class EventPublisher
{
// 声明一个事件
public event EventHandler MyEvent;
// 触发事件
protected virtual void OnMyEvent()
{
MyEvent?.Invoke(this, EventArgs.Empty);
}
}
public class EventSubscriber
{
public void Subscribe(EventPublisher publisher)
{
publisher.MyEvent += new EventHandler(EventHandlerMethod);
}
private void EventHandlerMethod(object sender, EventArgs e)
{
// 事件处理逻辑
}
}
3、C#静态构造函数特点是什么
最先被执行的构造函数,且一个类只允许有一个无参的静态构造函数。
执行顺序:静态变量>静态构造函数>实例变量>实例构造函数
4、CTS、CLS、CLR分别作何解释
CTS(Common Type System) :公共类型系统。
是.NET框架中定义所有数据类型的基础结构。定义了一套统一的数据类型规范:Int32、Int->string、Boolean->bool。
CLS(Common Language Specification) :公共语言规范。
是CTS的一个子集,它定义了一组规则,确保不同语言编写的程序能够在.NET环境中无缝协作。CLS规定了哪些特性是所有.NET语言都必须支持的,比如基本的数据类型、继承、接口等。如果一个语言完全遵循了CLS,那么用这个语言编写的程序就可以与其他遵循CLS的语言编写的程序一起工作,而不会存在兼容性问题。
CLR(Common Language Runtime):公共语言运行时。CLR是.NET框架的核心组件,提供了代码执行和管理的环境。负责代码的编译(JIT编译)、执行、垃圾回收、异常处理、安全性等。
5、C#中什么是值类型和引用类型
值类型:直接存储数据值。包括:struct,enum,int,float,char,bool,decimal。可以分配在栈上,减少垃圾回收。
引用类型:存储对数据的引用,而不是数据本身。包括:class,delegate,interface,array,object,string。分配在堆上,可能需要GC进行管理。
6、请详述在C#中类(class)与结构(struct)的异同
1)内存管理:
类:是引用类型,存储在堆(Heap)上。类的实例化需要分配堆内存,并使用引用(指针)访问。
结构:是值类型,存储在栈(Stack)上。结构的实例化直接分配在栈上或被复制到局部变量中。
2)默认值:
类:默认情况下,类的实例如果未显式初始化,其引用将为 null。
结构:默认情况下,结构的所有字段将自动初始化为其类型的零值。
3)构造函数:
类:可以有多个构造函数,用于不同的初始化方式。
结构:也可以有多个构造函数,但默认情况下会自动生成一个无参数的构造函数,将所有字段初始化为零值。
4)赋值和复制:
类:赋值操作复制的是引用(指针),即使使用 == 比较两个类的实例,比较的也是它们引用的内存地址。
结构:赋值操作创建的是结构的副本,使用 == 比较结构实例时,实际上是在比较它们的字段值。
5)使用场景:
类:适用于创建具有复杂行为的对象,或者需要继承和多态特性的场景。
结构:适用于存储轻量级数据,且不需要继承和多态特性的场景
7、new关键字的作用
运算符:创建对象实例
修饰符:在派生类定义一个重名的方法,隐藏掉基类方法
约束:泛型约束定义,约束可使用的泛型类型。
8、int?和int有什么区别
int?为可空类型,默认值可以是null
int默认值是0
int?是通过int装箱为引用类型实现
9、C#中值传递与引用传递的区别是什么
值传递时,系统首先为被调用方法的形参分配内存空间,并将实参的值按位置一一对应复制给形参,此后,被调用方法中形参值得任何改变都不会影响到相应的实参。
引用传递时,系统不是将实参本身值复制后传递给形参,而是将其引用值(即地址值)传递给形参,因此,形参所引用的该地址上的变量与传递的实参相同,方法体内相应形参值得任何改变都将影响到作为引用传递的实参。
可以通过ref和out来决定参数是否按照引用传递。
10、C#中参数传递ref与out的区别
1)ref指定的参数在函数调用时必须先初始化(但这是从C# 7.0开始的要求),而out不用。
2)out指定的参数在进入函数时会清空自己,因此必须在函数内部进行初始化赋值操作,而ref不用
总结:ref可以把值传到方法里,也可以把值传到方法外;out只可以把值传到方法外。
11、C#中什么是装箱和拆箱
装箱:把值类型转换成引用类型
拆箱:把引用类型转换成值类型
在装箱时不需要显示类型转换,拆箱需要显式的类型转换。
int i=0;
System.Object obj=i;//装箱
int j=(int)obj;//拆箱
12、C#实现多态的过程中overload重载与override重写的区别
重载:是方法的名称相同,参数或参数类型不同,进行多次重载以适应不同的需要;重载是面向过程的概念。
重写:是对基类中虚方法进行重写。重写是面对对象的概念。
13、C#中static关键字的作用
对类有意义的字段和方法使用static关键字修饰,称为静态成员,通过类名加访问操作符"."进行访问;对类的实例有意义的字段和方法不加static关键字,则称为非静态成员或实例成员。
注:静态字段在内存中只有一个拷贝,非静态字段则是在每个实例对象中拥有一个拷贝。而方法无论是否为静态,在内存中自会有一份拷贝,区别只是通过类名来访问还是通过实例名访问。
14、C#成员变量和成员函数前加static的作用
它们被称为常成员变量和常成员函数,又称为类成员变量额类成员函数。
分别用来反映类的状态。
比如类成员变量可以用来统计类实例的数量,类成员函数。负责这种统计的动作,不用new。
15、C#中索引器的实现过程,是否只能根据数字进行索引
C#通过索引器,可以像处理数组一样处理对象。索引器的实现基于类或结构体的属性,并且可以定义一个或多个参数来指定索引。特别是属性,每个元素都以一个get或set方法暴露。索引补单能索引数字(数组下标),还能索引一些HashMap的字符串。通常来讲,C#中类的索引器只有一个就是THIS,但也可以有无数个。索引器最大好处是使代码更自然,更符合实际思考模式。
示例:
public class MyClass
{
private Dictionary<int, string> _data;
public MyClass()
{
_data = new Dictionary<int, string>();
}
public string this[int index]
{
get { return _data[index]; }
set { _data[index] = value; }
}
}
MyClass myObject = new MyClass();
myObject[0] = "Hello"; // 使用索引器赋值
string value = myObject[0]; // 使用索引器访问
16、C#中abstract class抽象类和interface接口有什么区别
abstract声明抽象类抽象方法,一个类中有抽象方法,这个类就是抽象类。抽象方法就是不含主体,无实现方法,必须由继承者重写。抽象类不能实例化,只能通过继承被子类重写。
interface声明接口,只提供方法规则。
区别:
1、interface中不能有字段,而abstract class可以有;2、interface中不能有public等修饰符,而abstract class可以有;3、interface可以实现多继承,abstract class不可以。
17、C#中sealed修饰类有什么特点
密封,不能继承,性能优化。
public class BaseClass
{
public virtual void Display()
{
Console.WriteLine("Display method of BaseClass");
}
}
public sealed class SealedClass : BaseClass
{
public override void Display()
{
Console.WriteLine("Display method of SealedClass");
}
}
// 下面的代码将导致编译错误,因为 SealedClass 是 sealed 的
// public class DerivedClass : SealedClass
// {
// }
18、字符串中string str=null和string str=""和string str=string.Empty的区别
string.Empty相当于"",Empty是一个静态只读的字段,不会抛出 NullReferenceException。string str="",初始化对象,并分配一个空字符串的内存空间string str=null。初始化对象,不会分配内存空间,可能会抛出 NullReferenceException。
19、byte b= 'a';byte c = 1; byte d = 'ab';byte e='啊';byte g = 256;这些变量有些错误,错误在哪
本题考查的是数据类型能承载数据的大小。
1byte = 8bit,一个汉字=2个byte,一个英文=1个byte=8bit
1)byte b = 'a'; - 正确。字符 'a' 在ASCII码表中对应的十进制数值是97,这是一个有效的 byte 类型的值。
2)byte c = 1; - 正确。数字1在0到255的范围内,可以赋值给 byte 类型的变量。
3)byte d = 'ab'; - 错误。C#不支持将两个字符的字符串(如 'ab')直接赋值给 byte 类型的变量。如果尝试这样做,将会导致编译错误,因为编译器期望 byte 类型的值是一个8位的数字。
4)byte e = '啊'; - 错误。字符 '啊' 是一个Unicode字符,其编码值超出了ASCII码的范围。在UTF-8编码中,'啊' 的编码可能需要多个字节来表示,因此不能直接赋值给 byte 类型的变量。
5)byte g = 256; - 错误。数字256不在 byte 类型允许的0到255的范围内。尝试将256赋值给 byte 类型的变量会导致编译错误,因为超出了 byte 类型能表示的最大值。
20、string和StringBuilder区别,两者性能比较
都是引用类型,分配在堆上
string 是一个不可变的引用类型。这意味着一旦创建了一个 string 对象,就不能更改它的内容。每次对字符串进行修改操作时,实际上都会创建一个新的 string 对象。对于少量的字符串操作,使用 string 是简单且方便的。
StringBuilder是一个可变的引用类型,用于在运行时构建字符串。它允许对字符串进行修改而不需要创建新的字符串对象。在字符串操作频繁的场景下(如循环中构建字符串)更加高效,因为它减少了内存分配和垃圾回收的压力。
总结:对于简单的、不需要修改的字符串操作,使用 string 更为合适。对于复杂的、需要频繁修改的字符串操作,使用 StringBuilder 更为高效。
21、什么是扩展方法
扩展方法(Extension Methods)是一种特殊的静态方法,它们为现有类型提供了额外的功能,而不需要修改原始类型。
示例:假设我们想为 int 类型添加一个方法来执行简单的平方运算,我们可以这样定义一个扩展方法:
public static class IntExtensions
{
public static int Square(this int number)
{
return number * number;
}
}
int number = 5;
int result = number.Square(); // 调用扩展方法,结果为25
22、特性是什么?如何使用
特性与属性是完全不同的两个概念,只是在名称上比较相近。Attribute特性就是关联一个目标对象的配置信息,本质上是一个类,为目标元素提供关联附加信息,这段附加信息存储在dll内的元素据,本身没什么意义。运行期以发射方式获取附加信息。
23、应用程序域(AppDomain)
一种边界,它由公共语言运行库围绕同一应用程序范围内创建的对象建立。每个应用程序域都有自己独立的内存空间和执行环境,这意味着在同一个进程中可以同时运行多个应用程序域,每个应用程序域可以加载和执行不同的代码。
// 创建新的应用程序域
AppDomain newDomain = AppDomain.CreateDomain("MyDomain");
// 在新的应用程序域中创建对象实例
object result = newDomain.CreateInstanceAndUnwrap(
typeof(MyClass).Assembly.FullName,
typeof(MyClass).FullName);
// 调用新域中对象的方法
MyClass myObject = (MyClass)result;
myObject.MyMethod();
// 卸载应用程序域
AppDomain.Unload(newDomain);
应用程序域在.NET应用程序中使用较少,因为它们增加了复杂性,并且可能影响性能。然而,在需要严格隔离和安全策略的大型应用程序中,应用程序域可以发挥重要作用。
24、byte a = 255;a+=5;a的值是多少
byte的取值范围是-2的8次方至2的8次方-1,-256至258,a+=1时,a的值是0,所以a+=5时,值是4
25、const和readonly有什么区别
都可以标识常量,区别如下:
1、初始化位置不同。const必须在声明时赋值,readonly在声明时或者构造函数进行初始化。
2、修饰对象不同。const即可以修饰类的字段,也可以修饰局部变量;readonly只能修饰类的字段。
3、const是编译时常量,在编译时确定值;readonly运行时常量,运行时确定值。
4、const默认静态;readonly需要显示声明静态。
5、修饰引用类型不同。const只能修饰string或者null的其他引用类型;readonly可以任意类型。
26、下面代码,a,b值是多少
string strTmp ="a1某某某";
int a=System.Text.Encoding.Default.GetBytes(strTmp).Length;
int b=strTmp.Length;
分析:一个字母、数字占一个byte,一个中文占两个byte,所以a=8,b=5
27、String s=bew String("yyds");创建了几个String Object?
两个对象,一个是"yyds",一个是指向"yyds"的引用对象s。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具