C# 面试考点

C#强基础面试

1. 类的执行顺序

静态成员变量初始化 -> 静态构造函数 -> 实例成员变量初始化 -> 实例构造函数

  • 如果有基类,先按上述顺序(递归地)初始化基类(从最基础的类开始,依次向下)。
  • 初始化当前类的静态成员变量。
  • 执行当前类的静态构造函数。
  • (创建实例时)初始化当前类的实例成员变量。
  • (创建实例时)执行当前类的实例构造函数。

2. 事件的多个处理器执行顺序

按事件的绑定顺序同步执行,除非处理器内部实现了异步处理

像RabbitMQ的多个消费者的Received事件的并发处理,是RabbitMQ的设计和消息队列的并发机制实现的。

3. 多线程锁有哪些,区别是什么

lock(Monitor)、Mutex、Semaphore、ReaderWriterLock、SpinLock、volatile

4. 线程安全的集合有哪些

  • ConcurrentQueue

一个先进先出(FIFO)队列,提供了线程安全的Enqueue和Dequeue操作。

  • ConcurrentStack

一个后进先出(LIFO)堆栈,提供了线程安全的Push和Pop操作。

  • ConcurrentBag

一个允许高效并发添加和遍历元素的无序集合,不过不是按顺序访问。

  • ConcurrentDictionary<TKey, TValue>

一个线程安全的哈希表,提供并发读取和写入操作,包括添加、移除和更新键值对。

  • BlockingCollection

一种集合包装器,结合了生产者-消费者模式,可以在添加和获取元素时进行阻塞或限制集合大小。

5. 结构(struct)和类(class)的相同点、差异点

在.NET中,结构(struct)和类(class)都是数据结构,它们可以封装数据和行为(方法)。尽管它们在很多方面都是相似的,但也有一些关键的差异,这些差异影响了它们的使用和性能特性。下面是结构和类的相同点和差异:

  • 相同点
  1. 成员:结构和类都可以包含方法、字段、属性、索引器、事件、操作符重载等成员。
  2. 继承:结构和类都可以实现接口。
  3. 构造函数:结构和类都可以定义构造函数。
  • 差异
  1. 内存分配

    • 是引用类型,它们的实例在托管堆上分配内存。类的变量实际上持有对对象实例内存地址的引用。
    • 结构是值类型,它们的实例通常在声明它们的方法的栈上分配内存(除非它们是另一个类的成员,这种情况下它们在堆上作为那个类的一部分分配)。结构的变量直接包含它们的数据。
  2. 继承

    • 可以从其他类继承,支持多态和继承链。
    • 结构不能从其他结构或类继承,并且所有结构隐式地从System.ValueType继承,而System.ValueType最终继承自System.Object
  3. 默认构造函数

    • 可以没有定义任何构造函数,此时编译器会自动生成一个默认的无参构造函数。
    • 结构总是有一个默认的无参构造函数,用于初始化所有值类型字段为其默认值,且不能被重写。
  4. 内存语义

    • 类的赋值涉及引用的复制,两个类类型的变量可以引用堆上的同一个对象实例,因此一个变量的改变会影响另一个变量。
    • 结构的赋值会创建一个新的实例副本,所以一个结构变量的改变不会影响另一个。
  5. 装箱和拆箱

    • 作为引用类型,不涉及装箱和拆箱操作。
    • 结构作为值类型,当它们被赋值给一个object类型或者任何接口类型时,会发生装箱操作。相反,当一个装箱的值类型被转换回其原始类型时,会发生拆箱操作。
  6. 性能

    • 的使用可能涉及到更多的堆内存分配和垃圾回收,这可能会影响性能。
    • 结构由于通常在栈上分配,且值类型的赋值涉及到实例的完整复制,它们在某些场景下可能提供更好的性能。但是,如果结构很大,频繁的复制可能会导致性能下降。
  • 使用场景

    • 适合用作复杂的数据结构,需要通过引用共享数据时,或当你需要利用继承和多态时。
    • 结构适合用于小型、不可变的数据载体,特别是那些希望避免额外的堆分配和垃圾回收开销的场景。

选择结构还是类主要取决于你的特定需求,包括你的性能要求、数据大小、是否需要继承和多态等因素。

posted @ 2024-03-27 14:27  Nine4酷  阅读(19)  评论(0编辑  收藏  举报