当前位置:   article > 正文

.Net_C#面试题(一)

.Net_C#面试题(一)

1.C#中ref和out有什么区别

答:

  • 都是按引⽤类型进⾏传递

  • 属性不是变量不能作为out、ref参数传递

  • ref参数必须初始化。out不需要初始化

  • 当⽅法有多个返回值时,out⾮常有⽤

 2.class和struct的区别及使用场景

答:

相同点

  • 都可以实现接⼝

不同点

  • class是引⽤类型,struct是值类型
  • class允许继承、被继承,struct不允许继承,只能继承接⼝

  • class可以初始化变量,struct不可以

  • class可以有⽆参的构造函数,struct不可以,必须是有参的构造函数,⽽且在有参的构造函数必须初始化所有成员
使⽤场景
  • Class⽐较适合⼤的和复杂的数据,表现抽象和多级别的对象层次时
  • Struct适⽤于作为经常使⽤的⼀些数据组合成的新类型,表示诸如点、矩形等主要⽤来存储数据的轻量级对象时,偏简单值
  • Struct有性能优势,Class有⾯向对象的扩展优势

3.抽象类和接⼝有什么区别

答:

抽象类(Abstract Class)

  • 抽象类是一个不能被实例化的类,它至少包含一个抽象方法(没有实现的方法)
  • 抽象类可以包含非抽象方法、字段、属性、事件和索引器
  • 抽象类可以作为其他类的基类,要求派生类实现所有的抽象方法
  • 抽象类可以包含构造函数,用于初始化派生类在创建实例时需要的一些通用状态
  • 抽象类可以实现接口

接口(Interface)

  • 接口是一种定义方法、属性、事件和索引器的契约,它不能被实例化
  • 接口中的所有成员都是隐式地公开的(public),并且都是抽象的,没有具体的实现
  • 接口不能包含字段或具有实现的方法(从C# 8.0开始,接口可以包含默认实现的方法,但这仍然是例外情况)
  • 类可以实现多个接口,并通过提供接口中所有成员的具体实现
  • 接口主要用于定义行为,允许对象之间进行松耦合的通信

区别

  • 实现:抽象类可以包含非抽象成员的实现,而接口只能定义成员,不能包含实现
  • 继承:一个类只能继承自一个抽象类,但可以实现多个接口
  • 构造函数:抽象类可以有构造函数,而接口没有
  • 成员访问修饰符:在接口中,所有成员默认都是public的,而在抽象类中,成员可以有不同的访问修饰符(如public、protected、internal等)
  • 默认值:从C# 8.0开始,接口可以有默认实现的方法,这意味着接口成员可以有默认值,但抽象类不能有默认实现的方法
  • 使用场景:抽象类通常用于表示一种“是”的关系,例如“猫是一种动物”,而接口用于表示一种“能做”的关系,例如“猫能跳”

4.解释一下C#匿名类,有什么好处

答:

在C#中,匿名类(Anonymous Type)是一种没有显式定义名称的类,它主要用于在需要一次性使用的简单对象创建场景中,比如当你要在LINQ查询中返回一组数据,或者需要临时存储一组键值对时

匿名类的好处

  • 简洁:匿名类允许你快速创建对象,而不需要先定义一个显式的类。这减少了代码量,并使得代码更加简洁
  • 一次性使用:匿名类通常用于一次性操作,比如在查询数据库后返回结果集。因为它们不需要在其他地方重复使用,所以不需要为它们定义持久的类
  • 即时使用:需要提前声明和定义类,可以立即创建和使用对象。这特别适用于快速原型开发或测试场景
  • 灵活性:匿名类可以根据需要包含任意数量和类型的属性和方法。这使得它们非常适合表示具有特定字段和行为的临时对象
  • 减少代码冗余:当你只需要一个对象的短暂表示时,避免创建不必要的持久类可以减少代码冗余和维护成本
  • 与LINQ协同工作:在LINQ查询中,匿名类经常用于选择特定的字段来创建新的对象集合,这些对象集合不需要在查询之外使用

需要注意的是,因为匿名类是隐式类型(var关键字用于声明),所以编译器会为每个匿名类生成一个独特的、不可见的名字,并且在同一作用域内,两个不同的匿名类即使看起来结构相同,它们也被视为不同的类型。因此,匿名类主要用于临时和局部的场景,而不是长期的对象模型设计

5.C#前台线程和后台线程有什么区别

答:

前台线程(Foreground Thread)

  • 前台线程是应用程序的主执行线程,通常是启动应用程序时自动创建的主线(MainThread)
  • 当应用程序中所有的前台线程都执行完毕后,应用程序才会终止
  • 应用程序的主入口点(如static void Main(string[] args))总是在一个前台线程上运行
  • 如果没有显式地指定线程类型,新创建的线程默认为前台线程

后台线程(Background Thread)

  • 后台线程是应用程序的辅助线程,它们用于执行非关键性的任务,如数据加载、文件操作等
  • 后台线程对于应用程序的终止来说不是必需的。当应用程序中所有的前台线程都结束时,即使后台线程仍在运行,应用程序也会立即终止
  • 后台线程通常用于执行那些即使被中断也不会影响应用程序主要功能的任务
  • 在C#中,可以通过设置Thread类的IsBackground属性来指示一个线程是否为后台线程

区别

  • 生命周期:前台线程的生命周期与应用程序的生命周期紧密相关,而后台线程则可能在应用程序终止时仍在运行
  • 终止行为:当所有前台线程结束时,应用程序终止。而后台线程则会在所有前台线程结束后被自动终止:即使它们可能还没有完成其工作
  • 用途:前台线程通常用于执行应用程序的主要逻辑,而后台线程用于执行非关键性或支持性的任务
  • 创建方式:默认情况下,新创建的线程是前台线程,需要通过设置IsBackground属性为true来显式地将线程标记为后台线程

在C#中使用线程时,根据任务的性质选择适当的线程类型是很重要的。例如,如果你有一个需要长时间运行的任务,但它不是应用程序的主要功能,那么将其放在后台线程中执行可能是一个好主意,这样即使这个任务没有完成,用户也可以关闭应用程序。然而,对于关键任务或需要确保完成的任务,使用前台线程更为合适

6.为什么GUI不⽀持跨线程调⽤?有什么解决⽅法

答:

GUI(图形用户界面)不支持跨线程调用的主要原因是为了保证UI控件的线程安全。GUI框架通常有一个特殊的线程处理模型,其中UI控件只能在特定的线程(通常是主线程或GUI线程)上被访问和修改。这是为了避免数据竞争、不一致以及其他并发问题,确保UI的稳定性和可预测性,如果从一个非UI线程直接调用GUI控件的方法,可能会导致不可预知的行为,如界面卡顿、响应缓慢、崩溃或数据不一致等。

解决⽅法

1.使用控件提供方法

  • 在WinForms中,可以使用控件的Invoke方法来在UI线程上执行委托
  • 在WPF中,可以使用Dispatcher.Invoke或Dispatcher.BeginInvoke来在UI线程上执行操作

2.使用 BackgroundWorker

  • BackgroundWorker是一个帮助在后台线程上执行操作同时提供简单的进度报告和错误处理的组件。它提供了DoWorkProgressChangedRunWorkerCompleted等事件,可以在UI线程上安全地更新UI

3.使用 SynchronizationContext

  • SynchronizationContext是一个抽象类,它提供了一种将执行上下文与特定的线程相关联的方式。在UI线程上获取SynchronizationContext的实例,然后在非UI线程上使用该实例来发布需要在UI线程上执行的操作

4.使用消息队列

  • 将所有对GUI的更新请求放入一个消息队列中,然后由一个单独的UI线程负责处理这些请求。这样可以确保所有对GUI的更新操作都在UI线程上按顺序执行

5.使用事件驱动模型

  • 定义事件和相应的事件处理函数,将UI更新的请求转化为事件。非UI线程通过触发这些事件来请求UI更新,而UI线程则负责处理这些事件

6.使用线程间通信机制

  • 使用诸如互斥锁(Mutex)、信号量(Semaphore)等同步机制来控制对GUI资源的访问。这可以确保在任何时候只有一个线程在更新UI

7.异步更新UI

  • 将UI的更新操作放入一个单独的线程或线程池中进行异步处理。当异步操作完成后,通过回调函数或事件通知机制来通知UI线程进行更新

7.C#中Thread 类有哪些常⽤的属性和⽅法

答:

常用属性

  • IsAlive:返回一个布尔值,表示线程是否处于活动状态(即是否已经启动且尚未终止)
  • IsBackground:一个布尔属性,用于获取或设置一个值,该值指示线程是否应该作为后台线程运行。后台线程不会阻止应用程序的终止
  • ManagedThreadId:获取一个唯一的标识符,该标识符是在线程启动时由公共语言运行时 (CLR) 分配给线程的
  • Name:获取或设置线程的名称,这可以用于调试和日志记录
  • Priority:获取或设置线程的调度优先级
  • ThreadState:获取一个ThreadState枚举值,表示线程的当前状态

常用方法

  • Start():启动线程。如果线程已经启动,则此方法将抛出ThreadStateException异常
  • Join():阻塞调用线程,直到当前线程终止为止。这通常用于确保主线程等待其他线程完成其任务
  • Join(int millisecondsTimeout):类似于Join(),但是有一个超时参数,指定调用线程等待的最大时间
  • Abort():请求终止线程。这不是一个推荐的做法,因为它可能会导致线程不安全地终止,并可能不执行正常的清理工作
  • ResetAbort():取消之前通过Abort()方法发出的终止请求
  • Sleep(int millisecondsTimeout):使当前线程暂停执行指定的时间
  • Interrupt():中断处于WaitSleepJoin状态的线程
  • BeginCriticalRegion()EndCriticalRegion():这两个方法用于标记代码段的开始和结束,其中线程应该不被中断。它们主要用于确保线程在执行关键代码时不被意外中断
  • BeginThreadAffinity()EndThreadAffinity():这两个方法用于确保线程在其执行的代码段期间仅在其初始处理器上运行

在使用Thread类时,还需要注意线程安全和资源同步的问题。为了避免竞态条件和死锁,你可能需要使用诸如lock语句、Monitor类、Mutex类、Semaphore类、ManualResetEvent类和AutoResetEvent类等同步机制,此外,C#还提供了更高级的并发和异步编程模型,如Task Parallel Library(TPL)和async/await模式,它们使得创建和管理多线程应用程序变得更为简单和高效。在可能的情况下,建议使用这些更现代的并发模型,而不是直接使用Thread

8.Silverlight 和 WPF的异同

答:

Silverlight和WPF(Windows Presentation Foundation)都是微软开发的技术,用于创建富互联网应用程序(RIA)和桌面应用程序的用户界面。

相似之处

  • 编程模型:Silverlight和WPF都基于相同的编程模型,即使用XAML(可扩展应用程序标记语言)来描述用户界面,并与C#或VB.NET等编程语言结合使用
  • 控件:两者都提供了一套丰富的控件,如按钮、文本框、列表框等,用于构建用户界面
  • 数据绑定:Silverlight和WPF都支持数据绑定,这使得它们能够轻松地将UI元素与数据源连接起来

不同之处

  • 运行环境:Silverlight是一个浏览器插件,只能在支持它的浏览器中运行。而WPF则可以在Windows桌面上直接运行,作为独立的.exe文件
  • 功能限制:由于Silverlight是设计为在浏览器中运行的,因此它的一些功能受到了限制。例如,Silverlight不支持直接访问本地文件系统或注册表等。相比之下,WPF作为桌面应用程序框架,具有更强大的功能
  • 性能:由于WPF是直接在Windows桌面上运行的,因此它在性能上通常优于Silverlight。Silverlight在浏览器中运行时,可能会受到浏览器本身的性能限制
  • 版本支持:WPF在Windows Vista和Windows XP SP2等较旧的操作系统上也能运行,而Silverlight则需要较新版本的浏览器支持

总的来说,Silverlight和WPF在编程模型、控件和数据绑定等方面有许多相似之处,但在运行环境、功能限制、性能和版本支持等方面存在一些差异。选择使用哪种技术取决于您的具体需求,例如是否需要跨浏览器运行、是否需要访问本地资源等

9.解释这⼏个类的作⽤及关系: Visual, UIElement, FrameworkElement, Control

答:

在WPF(Windows Presentation Foundation)中,Visual, UIElement, FrameworkElement, 和 Control 是几个关键类,它们共同构成了WPF的图形和界面系统。这些类的作用和关系如下

Visual 类

  • 作用:Visual 类是所有可视化对象的基类,这些对象在渲染系统中被表示。Visual 类表示一个可以在屏幕上绘制的对象,但它不包含任何与用户交互的逻辑。它主要负责渲染相关的操作,如绘制形状、图像和文本
  • 与其他类的关系:Visual 是WPF渲染树中的基础,UIElementFrameworkElement 都继承自 Visual,这意味着它们都有渲染的能力

UIElement 类

  • 作用:UIElement 类是所有用户界面元素的基类。它提供了基本的用户界面功能,如布局、输入事件处理、样式和动画。但是,UIElement 并不直接参与渲染过程,而是通过其子类 Visual 来实现
  • 与其他类的关系:UIElementFrameworkElement 和其他一些UI组件的基类。它提供了许多与用户界面交互相关的基础功能

FrameworkElement 类

  • 作用:FrameworkElement 类是WPF框架中更具体的UI元素基类。它提供了数据绑定、命令、样式、布局和事件处理等高级功能。FrameworkElement 是大多数WPF控件的基类,如按钮、文本框等
  • 与其他类的关系:FrameworkElement 继承自 UIElement,并添加了更多的功能。同时,Control 类也继承自 FrameworkElement,这意味着所有的 Control 实例都是 FrameworkElement 的实例

Control 类

  • 作用:Control 类是WPF控件库中控件的基类。它提供了控件的共同行为和外观,如背景、边框、字体等。大多数具体的控件,如 Button, TextBox, CheckBox 等,都继承自 Control
  • 与其他类的关系:Control 继承自 FrameworkElement,这意味着它继承了数据绑定、样式和布局等高级功能,并添加了控件特有的行为和外观属性

总结

  • Visual 负责渲染
  • UIElement 提供基础的用户界面功能
  • FrameworkElementUIElement 的基础上提供了更多的高级功能
  • ControlFrameworkElement 的基础上定义了控件的通用行为和外观

这些类之间的关系形成了一个层次结构,从最基础的 Visual 到更具体的 Control,每个类都添加了更多的功能和特性。在创建WPF应用程序时,会直接使用这些类或其子类来构建用户界面

10.什么是 XSS 攻击,如何避免

XSS攻击,全称跨站脚本攻击(Cross Site Scripting),是一种代码注入式攻击。攻击者通过在网站注入恶意脚本,使之在用户的浏览器上运行,从而盗取用户的信息如Cookie等。这种攻击通常发生在网站没有对恶意代码进行过滤,与正常的代码混合在一起时,浏览器没有办法分辨哪些脚本是可信的,从而导致了恶意代码的执行

XSS攻击类型

  • 存储型XSS攻击:恶意代码提交到了网站的数据库中,当用户请求数据的时候,服务器将其拼接为HTML后返回给了用户,从而导致恶意代码的执行。这种攻击的危害较大,因为只要访问了这个页面的访客,都有可能会执行这段恶意脚本
  • 反射型XSS攻击(也称为非持久型攻击):攻击者构建了特殊的URL,当服务器接收到请求时,从URL中获取数据,拼接到HTML后返回,从而导致了恶意代码的执行。这种攻击属于一次性攻击,仅对当次的页面访问产生影响
  • DOM型XSS攻击:攻击者构建了特殊的URL,用户打开网站后,JS脚本从URL在获取数据,从而导致了恶意代码的执行

避免XSS攻击

  • 对恶意代码提交的时候进行过滤处理。如果我们对存入数据库的数据都进行转义处理,可以在一定程度上防止XSS攻击。但是,这种方法并不完全可靠,因为有可能在多个地方使用同一份数据,而有的地方可能不需要转义处理
  • 在浏览器执行恶意代码的时候进行预防。一种方法是使用纯前端的方式,不用服务器端拼接后返回。另一种是对需要插入到HTML中的代码做好充分的转义,防止恶意代码的执行。此外,还可以使用CSP(Content Security Policy)来防止恶意代码的注入攻击,CSP的本质是建立一个白名单,告诉浏览器哪些外部资源可以进行加载和执行

总的来说,避免XSS攻击需要综合考虑多个方面,包括输入数据的过滤处理、输出数据的转义处理、使用安全的编程实践等。同时,也需要不断更新和升级网站的安全措施,以应对不断变化的攻击手段

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/191296
推荐阅读
相关标签
  

闽ICP备14008679号