.NET/C#⾯试题汇总系列:集合、异常、泛型、LINQ、委托、EF!(完整版)

1.IList 接⼝与List的区别是什么?

  • 定义与继承关系‌:

    • IList<T> 是一个接口,定义了一组对象的集合,这些对象可以通过索引进行访问,并且支持插入、删除和搜索等操作。它继承自 ICollection<T>IEnumerable<T>,以及它们的非泛型版本。
    • List<T> 是一个类,实现了 IList<T> 接口。它提供了接口中定义的所有方法的具体实现,并添加了一些额外的功能,如排序、搜索等。
  • 功能与灵活性‌:

    • 使用 IList<T> 接口时,你的代码更加灵活,因为它不依赖于具体的实现类(如 List<T>)。这意呀着你可以轻松地更换底层的数据存储结构,只要它实现了 IList<T> 接口。
    • List<T> 提供了更多的功能和性能优化,因为它是具体的实现类。但是,这也意味着你的代码与 List<T> 紧密耦合,更换数据存储结构时可能需要更多的工作。
  • 使用场景‌:

    • 当你的代码需要处理一个集合,但你不关心这个集合是如何实现的,或者你希望你的代码能够轻松地与不同的集合实现一起工作时,使用 IList<T> 接口是更好的选择。
    • 当你需要利用 List<T> 提供的特定功能(如 SortFind 等)时,或者当你确定你的应用程序将始终使用 List<T> 作为数据存储时,直接使用 List<T> 类可能更方便。

2.泛型的主要约束和次要约束是什么?

当⼀个泛型参数没有任何约束时,它可以进⾏的操作和运算是⾮常有限的,因为不能对实参进⾏任何类型 上的保证,这时候就需要⽤到泛型约束。泛型的约束分为:主要约束和次要约束,它们都使实参必须满⾜ ⼀定的规范,C#编译器在编译的过程中可以根据约束来检查所有泛型类型的实参并确保其满⾜约束条件。
主要约束

⼀个泛型参数⾄多拥有⼀个主要约束,主要约束可以是⼀个引⽤类型、class或者struct。如果指定⼀个引 ⽤类型(class),那么实参必须是该类型或者该类型的派⽣类型。相反,struct则规定了实参必须是⼀个 值类型。

次要约束

次要约束主要是指实参实现的接⼝的限定。对于⼀个泛型,可以有0到⽆限的次要约束,次要约束规定了实 参必须实现所有的次要约束中规定的接⼝。

cs 复制代码
public class MyGenericClass<T> where T : class, IMyInterface // 引用类型约束和接口约束
{
    // ...
}

public interface IMyInterface
{
    // ...
}

在这个例子中,MyGenericClass的泛型类型参数T被约束为必须是引用类型,并且必须实现IMyInterface接口。这同时使用了主要约束(引用类型约束)和次要约束(接口约束)。

3. 如何把⼀个array复制到arrayist⾥?

cs 复制代码
foreach( object arr in array)
{
    arrayist.Add(arr);
}

4.List, Set, Map是否继承⾃Collection接⼝?

List, Set,是否继承自Collection接口,Map不是。

  • List:
    • 1.可以允许重复的对象。
    • 2.可以插入多个null元素。
    • 3.是一个有序容器,保持了每个元素的插入顺序,输出的顺序就是插入的顺序。
    • 4.常用的实现类有 ArrayList、LinkedList 和 Vector。ArrayList 最为流行,它提供了使用索引的随意访问,而 LinkedList 则对于经常需要从 List 中添加或删除元素的场合更为合适。
  • Set:
    • 1.不允许重复对象
    • 2.无序容器,你无法保证每个元素的存储顺序,TreeSet通过 Comparator 或者 Comparable 维护了一个排序顺序。
    • 3.只允许一个 null 元素
    • 4.Set 接口最流行的几个实现类是 HashSet、LinkedHashSet 以及 TreeSet。
  • Map:
    • 1.Map不是collection的子接口或者实现类。Map是一个接口。
    • 2.Map 的 每个 Entry 都持有两个对象,也就是一个键一个值(键值对),Map 可能会持有相同的值对象但键对象必须是唯一的。
      1. TreeMap 也通过 Comparator 或者 Comparable 维护了一个排序顺序。
      1. Map 里你可以拥有随意个 null 值但最多只能有一个 null 键。
    • 5.Map 接口最流行的几个实现类是 HashMap、LinkedHashMap、Hashtable 和 TreeMap。(HashMap、TreeMap最常用)

5. Set⾥的元素是不能重复的,那么⽤什么⽅法来区分重复与否呢? 是⽤==还是equals()? 它 们有何区别?

Set⾥的元素是不能重复的,那么⽤iterator()⽅法来区分重复与否。equals()是判读两个Set是否相等。 equals()和==⽅法决定引⽤值是否指向同⼀对像,equals()在类中被覆盖,为的是当两个分离的对象的内 容和类型相配的话,返回真值。

6.有50万个int类型的数字,现在需要判断⼀下⾥⾯是否存在重复的数字,请你简要说⼀下思路。

  1. 使用HashSet:创建一个HashSet对象,遍历整个数字集合,将每个数字添加到HashSet中。由于HashSet不允许重复元素,如果添加操作失败(即add方法返回false),则说明该数字已经存在于集合中,因此存在重复的数字。

  2. 排序后检查相邻元素:首先对数字集合进行排序,然后遍历排序后的集合,比较相邻的元素是否相等。如果发现相等的相邻元素,则说明存在重复的数字。

7.数组有没有length()这个⽅法? String有没有length()这个⽅法?

数组和字符串都使用Length属性来获取它们的长度,而不是length()方法

  • 数组没有length()这个方法。在C#中,获取数组的长度是通过其属性.Length来获取的。例如,对于一个整型数组arr,可以使用arr.Length来获取数组的长度。
  • String类有Length属性而不是length()方法。通过访问字符串对象的Length属性,可以获取字符串的长度,即字符的数量。例如,对于一个字符串s,可以使用s.Length来获取字符串的长度。

8.⼀个整数List中取出最⼤数(找最⼤值)。不能⽤Max⽅法。

遍历比较

这种方法通过遍历列表中的每个元素,并将当前元素与已知的最大值进行比较,从而找到最大值。如果当前元素大于已知的最大值,则更新最大值。

9. C#异常类有哪些信息?

C#异常类(通常继承自System.Exception类)

  1. Message 属性‌:这个属性包含了异常的描述性消息,是一个字符串类型。它是最常用于了解异常原因的属性之一。

  2. StackTrace 属性‌:这个属性提供了异常发生时调用堆栈的快照。调用堆栈是一个方法调用序列,展示了异常被抛出时的方法调用路径。这对于调试和定位问题非常有用。

  3. InnerException 属性 ‌:如果当前异常是由另一个异常引起的(即在一个异常的catch块中抛出了新的异常,并将原始异常作为新异常的InnerException),则此属性包含了对那个原始异常的引用。这允许你追踪异常的根源。

10. 如何创建⼀个⾃定义异常?

根据类继承原则和异常处理原则,我们可以使⽤以下⽅式来⾃定义⼀个类:

cs 复制代码
public class CustomException : Exception
{
}

11. 利⽤IEnumerable实现斐波那契数列⽣成?

cs 复制代码
IEnumerable<int> GenerateFibonacci(int n)
{
    if (n >= 1) yield return 1;

    int a = 1, b = 0;
    for (int i = 2; i <= n; ++i)
    {
        int t = b;
        b = a;
        a += t;

        yield return a;
    }
}

12.请利⽤ foreach 和 ref 为⼀个数组中的每个元素加 1

cs 复制代码
int[] arr= { 1, 2, 3, 4, 5 };
Console.WriteLine(string.Join(",",arr));
foreach (ref int i in arr.AsSpan())
{
    i++;
}
Console.WriteLine(string.Join(",", arr));

13.如何针对不同的异常进⾏捕捉?

  • 捕捉并处理文件读写异常
cs 复制代码
public void SafeReadFile(string filePath)
{
    try
    {
        // 尝试读取文件
        string content = System.IO.File.ReadAllText(filePath);
        Console.WriteLine($"文件内容: {content}");
    }
    catch (System.IO.FileNotFoundException ex)
    {
        Console.WriteLine($"文件未找到: {ex.Message}");
    }
    catch (System.IO.IOException ex)
    {
        Console.WriteLine($"读写文件时发生错误: {ex.Message}");
    }
    catch (Exception ex)
    {
        // 捕捉所有未处理的异常
        Console.WriteLine($"发生未知错误: {ex.Message}");
    }
}
  • 捕捉并处理网络请求异常
cs 复制代码
using System.Net.Http;
using System.Threading.Tasks;

public async Task<string> SafeWebRequest(string url)
{
    try
    {
        using (HttpClient client = new HttpClient())
        {
            HttpResponseMessage response = await client.GetAsync(url);
            response.EnsureSuccessStatusCode(); // 抛出异常如果响应状态码表示失败
            string responseBody = await response.Content.ReadAsStringAsync();
            return responseBody;
        }
    }
    catch (HttpRequestException ex)
    {
        Console.WriteLine($"网络请求错误: {ex.Message}");
        return null;
    }
    catch (TaskCanceledException ex)
    {
        Console.WriteLine($"网络请求超时或被取消: {ex.Message}");
        return null;
    }
    catch (Exception ex)
    {
        // 捕捉所有未处理的异常
        Console.WriteLine($"网络请求发生未知错误: {ex.Message}");
        return null;
    }
}
  • 捕捉并处理数据库操作异常

    cs 复制代码
    using System.Data.SqlClient;
    
    public void SafeDatabaseOperation(string connectionString, string query)
    {
        try
        {
            using (SqlConnection connection = new SqlConnection(connectionString))
            {
                connection.Open();
                using (SqlCommand command = new SqlCommand(query, connection))
                {
                    command.ExecuteNonQuery();
                }
            }
        }
        catch (SqlException ex)
        {
            // 根据SqlException的Number属性可以进一步区分错误类型
            Console.WriteLine($"数据库操作错误: {ex.Message}");
            if (ex.Number == -2) // 假设-2代表连接超时
            {
                Console.WriteLine("可能是数据库连接超时了。");
            }
        }
        catch (Exception ex)
        {
            // 捕捉所有未处理的异常
            Console.WriteLine($"数据库操作中发生未知错误: {ex.Message}");
        }
    }

14.如何避免类型转换时的异常?

  • 使用as关键字进行安全的类型转换:as关键字用于尝试将对象转换为指定的类型,如果转换失败,它会返回null而不是抛出异常。

    cs 复制代码
    object obj = "Hello";
    string str = obj as string; // 成功转换
    if (str != null)
    {
        Console.WriteLine(str);
    }
    else
    {
        Console.WriteLine("转换失败");
    }
  • 使用is关键字检查对象是否为特定类型的实例:is关键字用于检查对象是否属于指定的类型或实现了指定的接口。

    cs 复制代码
    object obj = "Hello";
    if (obj is string)
    {
        string str = (string)obj;
        Console.WriteLine(str);
    }
    else
    {
        Console.WriteLine("不是字符串类型");
    }

15.Serializable特性有什么作⽤?

Serializable 是一个属性(Attribute),用于指示一个类可以被序列化。序列化是将对象的状态信息转换为可以存储或传输的形式的过程,比如转换为二进制流或XML文档。反序列化则是这个过程的逆操作,即将存储或传输的信息恢复为原始对象。
作用:

  1. 持久化:通过将对象序列化到磁盘上,可以将其状态保存下来,以便稍后重新加载和使用。这对于需要长时间运行的程序非常有用,因为它允许程序在中断后恢复其状态。

  2. 远程调用:序列化的对象可以通过网络发送给远程计算机,然后在远程计算机上进行反序列化以恢复原始对象的状态。这允许在不同的系统之间共享数据和对象。

  3. 复制对象:序列化可以将对象转换为字节流,然后可以在内存中复制该字节流以创建对象的副本。这对于实现深拷贝非常有用,因为这样可以确保对象及其所有子对象都被正确地复制。

  4. 跨应用程序通信:序列化的对象可以作为参数传递给其他应用程序或组件,从而实现跨应用程序的通信和数据交换。

16.委托是什么?

委托是一种类型,它封装了对方法的引用。在C#中,委托(Delegate)是一种引用类型,它可以用来封装一个方法,并在需要时调用这个方法。

17.如何自定义委托?

委托(Delegate)是一种类型安全的函数指针,它允许将方法作为参数传递给其他方法,或者将方法作为其他方法的返回值。

  1. 定义委托类型
  2. ‌创建委托实例
  3. ‌调用委托
cs 复制代码
internal class Program
{
    static void Main(string[] args)
    {
        StrDelegate sd = GetTime;//2、创建委托实例
        string getsd = sd();//3、调用委托
        Console.WriteLine(getsd);
    }
    public delegate string StrDelegate();//1、定义委托类型
    public static string GetTime() {
        return DateTime.Now.ToString("HH:mm:ss");
    }
}

18 .NET默认的委托类型有哪⼏种?

**Action 委托(无返回值的委托)**‌

  • 用途‌:用于表示不返回任何值(即void返回类型)的方法。

  • 重载 ‌:Action 委托有多个重载版本,允许传递不同数量的参数(从0个到16个不等)。

  • 示例 ‌:

    cs 复制代码
    static void Main(string[] args)
    {
        EAction();
        EAction("你好");
    }
    public static void EAction()
    {
        Action action = () => { Console.WriteLine("Hello world"); };
        action();
    }
    public static void EAction(string message)
    {
        Action<string> action = (x) => { Console.WriteLine(message); };
        action(message);
    }

    **Func 委托(有返回值的委托)**‌

  • 用途‌:用于表示具有返回值的方法。

  • 重载 ‌:Func 委托有多个重载版本,每个版本都至少有一个输入参数(代表方法的输入),并有一个返回类型(代表方法的返回值)。输入参数的数量可以从0个到16个不等。

  • 示例 ‌:

    cs 复制代码
    Func<int, int, int> FAdd = (a, b) => { return a + b; };
    Console.WriteLine(FAdd(1, 2));//3
    Func<string, string> FMsg = (x) => { return "Hello" + x; };
    Console.WriteLine(FMsg("小明"));//Hello小明

19.什么是泛型委托?

泛型委托是一种特殊类型的委托,它允许你定义一个委托类型,该类型可以引用任何具有特定签名的方法,而不需要事先知道这些方法的参数类型或返回类型。泛型委托提供了一种灵活的方式来处理不同类型的方法调用,并提高了代码的重用性和类型安全性。

  • 有参数有返回值的泛型委托
cs 复制代码
static void Main(string[] args)
{
    // 2、创建一个泛型委托实例,用于引用两个整数相乘的方法
    MyDelegate<int, int, int> myDele = (x, y) => (x * y);
    //3、调用委托实例,执行乘法操作
    int result =myDele(3, 4);
}
//1、// 定义一个泛型委托,它接受两个整数参数并返回它们的乘积
public delegate TMyResult MyDelegate<T1,T2, TMyResult>(T1 x,T2 y);
  • 有参数无返回值的泛型委托
cs 复制代码
static void Main(string[] args)
{
    MyDelegate<string> my = (x) => { Console.WriteLine(x); };
    my("Hello");
}
public delegate void MyDelegate<T>(T t);
  • 无参数无返回值的泛型委托
cs 复制代码
static void Main(string[] args)
{
    MyDelegate<int> my = GetT<int>;
    Console.WriteLine(my());// 调用委托并输出返回值
}
public delegate T MyDelegate<T>();
public static T GetT<T>() { 
    return default(T);//返回默认值
}

20. 什么是匿名⽅法?

匿名⽅法是⽤作委托的参数的⼀段代码。

匿名方法是一种没有显式声明的名称但可作为委托参数或表达式树中的表达式的代码块

示例:

有参数有返回值的匿名方法

cs 复制代码
Func<int, int, int> Add = delegate(int a, int b)
{
    return a + b;
};

// 调用
int result = Add(5, 3);
Console.WriteLine(result); // 输出 8

21.什么是闭包?

通过Lambda表达式可以访问Lambda表达式块外部的变量,这成为闭包。 当引⽤外部变量时,需要注意,外部变量变化时,lambda表达式的结果也可能会随着外部变量变化⽽变 化。

例子:

  • int y = 5;
  • Func lambda = x => x + y;
  • Console.WriteLine(lambda(1));
  • y = 10;
  • Console.WriteLine(lambda(1));

22.EF(Entity Framework)是什么?

Entity Framework(简称EF)是微软提供的一个对象关系映射(ORM)框架,用于.NET应用程序。
主要有三种⽅式

  1. Database First"数据库优先"
  2. Model First"模型优先"
  3. Code First"代码优先"

EF的主要特点如下:

  1. 对象关系映射:EF将数据库表映射为.NET对象,使得开发者可以使用面向对象的方式来操作数据库。
  2. LINQ支持:EF支持使用LINQ查询来操作数据,提高了代码的可读性和编写效率。
  3. 变更跟踪:EF能够自动跟踪对象的变化,并生成相应的SQL语句来更新数据库。
  4. 延迟加载:EF支持延迟加载(Lazy Loading),只有在真正访问对象时才加载数据,提高了性能。
  5. 代码优先、模型优先和数据库优先:EF支持三种开发模式,可以根据项目需求选择合适的模式。
  6. 多个数据库提供商支持:EF支持多种数据库,如SQL Server、MySQL、PostgreSQL等。
  7. 与Visual Studio集成:EF与Visual Studio集成,提供了可视化的设计器和工具,方便开发者操作和管理数据模型。

23.什么是ORM?

ORM(对象关系映射,Object-Relational Mapping)是一种编程技术,用于将对象模型与数据库中的关系数据模型相互转换。

它使得开发者能够使用面向对象的方式来操作数据库,而不需要直接编写SQL语句。

ORM框架会自动生成相应的SQL语句并执行,从而使得数据访问更加高效。

  • O=>表实体
  • R=>数据库.表
  • M=>映射关系

优点

  1. 简化数据访问代码:ORM将数据库操作转换为对象操作,使得数据访问代码更简洁、易读。
  2. 提高开发效率:ORM提供了丰富的API和工具,减少了手动编写SQL语句的工作量。
  3. 跨数据库支持:ORM支持多种数据库,可以方便地切换数据库提供商。
  4. 自动处理事务:ORM框架可以自动处理事务,确保数据的完整性和一致性。
  5. 支持复杂的数据模型:ORM支持复杂的数据模型,如继承、关联等。
  6. 集成开发工具:ORM与开发工具集成,提供了可视化的设计器和工具,方便开发者操作和管理数据模型。

缺点

  1. 性能问题:ORM生成的SQL语句可能不是最优的,可能导致性能问题。
  2. 灵活性受限:ORM可能不支持某些特定的数据库特性或优化。
  3. 学习成本:ORM有一定的学习成本,需要了解其原理和使用方法。
  4. 代码冗余:ORM可能生成冗余的代码,增加了应用程序的体积。

24.为什么⽤EF⽽不⽤原⽣的ADO.NET?

  1. 简化数据访问代码:EF将数据库操作转换为对象操作,使得数据访问代码更简洁、易读。开发者可以使用面向对象的方式来操作数据库,而不需要编写SQL语句。

  2. 提高开发效率:EF提供了丰富的API和工具,减少了手动编写SQL语句的工作量。它支持LINQ查询,提高了代码的可读性和编写效率。

  3. 跨数据库支持:EF支持多种数据库,可以方便地切换数据库提供商。这使得应用程序更具灵活性,能够适应不同的数据库需求。

  4. 自动处理事务:EF框架可以自动处理事务,确保数据的完整性和一致性。这简化了事务管理的复杂性,并减少了出错的可能性。

  5. 支持复杂的数据模型:EF支持复杂的数据模型,如继承、关联等。这使得应用程序能够更好地处理复杂的数据关系,并提高数据的一致性。

  6. 集成开发工具:EF与开发工具(如Visual Studio)集成,提供了可视化的设计器和工具,方便开发者操作和管理数据模型。这提高了开发效率,并使得数据模型管理更加直观。

  7. 变更跟踪和延迟加载:EF能够自动跟踪对象的变化,并生成相应的SQL语句来更新数据库。它还支持延迟加载,只有在真正访问对象时才加载数据,提高了性能。

25.如何提⾼LINQ性能问题?

  • 选择合适的数据结构
  • 避免不必要的数据转换
  • **缓存结果:**如果某个LINQ查询会被频繁地调用,那么可以考虑将结果缓存起来,以减少数据库访问的次数。
  • 优化数据库
  • 使用分页

26.什么是协变和逆变?

可变性是以⼀种类型安全的⽅式,将⼀个对象作为另⼀个对象来使⽤。其对应的术语则是不变性 (invariant)。

可变性 : 可变性是以⼀种类型安全的⽅式,将⼀个对象作为另⼀个对象来使⽤。

例如对普通继承中的可变性:若某 ⽅法声明返回类型为Stream,在实现时可以返回⼀个MemoryStream。

可变性有两种类型:协变和逆变。

协变性

可以建⽴⼀个较为⼀般类型的变量,然后为其赋值,值是⼀个较为特殊类型的变量。

例如:

  • string str = "test";
  • object obj = str

逆变性:

在上⾯的例⼦中,我们⽆法将str和⼀个新的object对象画等号。如果强⾏要实现的话,只能这么 ⼲:

  • string s = (string) new object();

27.什么是IEnumerable?

  • IEnumerable及IEnumerable的泛型版本IEnumerable是⼀个接⼝,它只含有⼀个⽅法GetEnumerator。
  • Enumerable这个静态类型含有很多扩展⽅法,其扩展的⽬标是IEnumerable。
  • 实现了这个接⼝的类可以使⽤Foreach关键字进⾏迭代(迭代的意思是对于⼀个集合,可以逐⼀取出元素 并遍历之)。
  • 实现这个接⼝必须实现⽅法GetEnumerator。

28.IEnumerable的缺点有哪些?

  1. 性能问题: IEnumerable接口的实现通常需要额外的内存开销,因为它需要维护一个迭代器的状态。对于大型集合或需要频繁遍历的场景,这可能会导致性能下降。

  2. 类型限制: IEnumerable接口只能用于遍历集合,它不能提供其他集合操作,如添加、删除元素等。如果需要进行这些操作,你需要使用具体的集合类型(如List、Dictionary等)。

  3. 缺乏并发性支持:IEnumerable接口不支持并行遍历,这意味着在多线程环境中,多个线程无法同时遍历同一个集合。如果需要在多线程环境下处理集合,你可能需要使用其他并发集合类型(如ConcurrentBag、ConcurrentQueue等)。

  4. 缺乏延迟执行:IEnumerable接口的遍历是在调用GetEnumerator方法时立即开始的,而不是等到真正需要数据时才进行。这意味着如果你只需要部分数据,那么整个集合都会被遍历,即使只需要其中的一部分。

  5. 缺乏索引访问:IEnumerable接口没有提供直接通过索引访问集合元素的方法。如果你需要随机访问集合中的元素,那么你需要使用其他类型的集合,如数组或List。

28.延迟执行 (Lazy Loading)是什么?

通常与 LINQ(Language Integrated Query)一起使用,实现了查询的延迟执行。

这意味着当你创建一个 IEnumerable 查询时,查询本身不会立即执行,而是会等到需要遍历集合中的元素时才执行。这种机制在某些情况下可能会导致性能问题,尤其是在进行复杂或昂贵的操作时,因为每个元素在迭代时都可能重新计算。

29.LINQ可视化⼯具简单介绍⼀下?

LINQ(Language Integrated Query)是.NET框架中的一种查询技术,它允许开发者使用类似于SQL的语法来查询各种数据源,包括集合、数据库、XML等。

  1. LINQPad:LINQPad是一个免费的开源工具,提供了强大的LINQ查询编辑器和调试器。它支持多种编程语言,包括C#、VB.NET和F#,并且内置了丰富的示例代码库。LINQPad还提供了实时编译和执行的功能,使得开发者能够立即看到查询结果。

  2. SQL Server Data Tools (SSDT):如果你正在使用SQL Server作为数据存储,那么可以使用SQL Server Data Tools来进行LINQ查询的开发和调试。SSDT是一个集成开发环境(IDE),它提供了丰富的功能,包括数据库设计、查询构建、调试等。通过使用SSDT,你可以方便地将LINQ查询与数据库进行交互。

  3. Visual Studio:Visual Studio是微软官方提供的集成开发环境,它也支持LINQ查询的开发和调试。在Visual Studio中,你可以使用C#或VB.NET编写LINQ查询,并利用其强大的调试工具来检查和优化查询性能。

29.LINQ to Object和LINQ to SQL有何区别?

  • LINQ to SQL可以将查询表达式转换为SQL语句,然后在数据库中执⾏。
  • 相⽐LINQ to Object,则是将查 询表达式直接转化为Enumerable的⼀系列⽅法,最终在C#内部执⾏。
  • LINQ to Object的数据源总是实现 IEnumerable(所以不如叫做LINQ to IEnumerable),相对的,LINQ to SQL的数据源总是实现 IQueryable并使⽤Queryable的扩展⽅法。

30.除了EF,列举出你知道的ORM框架?

dapper EntityFramework、 EJB、Hibernate、IBATIS、TopLink、OJB

31.如何如何获取EF⽣成的Sql脚本?

  • 1.可以调试起来通过SqlServerProfiler 来获取Sql
  • 2.EF Dbcontext 注册⽇志事件输出⽇志查看Sql

32.在哪些类型额项⽬中你会选择EF? 为什么?

EF主要是以⾯向对象的思想来做数据库数据操作,对Sql语句能⼒没什么要求,开发使⽤效率⾼!便于上⼿,⼀般来说,使⽤EF框架,肯定会⽐直接使⽤ADO.NET,消耗的时间多⼀ 些。

所以在⼀般企业级开发,管理型系统,对数据性能要求不是特别⾼的情况下,优先选择EF,这样可以 ⼤⼤的推进开发效率!如果像⼀些互联⽹项⽬中,对性能要求精度很⾼!可以另外做技术选型,选择原⽣ ADO.NET

33.请说明EF中映射实体对象的⼏种状态?

  1. Detached:该实体未由上下⽂跟踪。刚使⽤新运算符或某个 System.Data.Entity.DbSet Create ⽅法创 建实体后,实体就处于此状态。
  2. Unchanged:实体将由上下⽂跟踪并存在于数据库中,其属性值与数据库中的值相同。
  3. Added:实体将由上下⽂跟踪,但是在数据库中还不存在。
  4. Deleted:实体将由上下⽂跟踪并存在于数据库中,但是已被标记为在下次调⽤ SaveChanges 时从数据 库中删除。
  5. Modified:实体将由上下⽂跟踪并存在于数据库中,已修改其中的⼀些或所有属性值。

34.如果实体名称和数据库表名不⼀致,该如何处理?

实体名称和数据库表名称不⼀致:可以通过使⽤TableAttribute 特性;

cs 复制代码
using System.ComponentModel.DataAnnotations;

[Table("数据库表名")]
public class 实体类名
{
    // 实体属性和方法
}

35. 泛型的优点有哪些?

代码的可重⽤性。⽆需从基类型继承,⽆需重写成员。 扩展性好。 类型安全性提⾼。 泛型将类型安全的负担从你那⾥转移到编译器。 没有必要编写代码来测试正确的数据类 型,因为它会在编译时强制执⾏。 降低了强制类型转换的必要性和运⾏时错误的可能性。

性能提⾼。泛型集合类型通常能更好地存储和操作值类型,因为⽆需对值类型进⾏装箱。

相关推荐
只想摆烂@27 分钟前
C# winfrom 如何多窗体优雅的回调方法
开发语言·c#
锋君3 小时前
C# 手动写入日志,过大写入新文件
c#
脚步的影子7 小时前
.NET 6.0 + WPF 使用 Prism 框架实现导航
.net·wpf
niaoma11 小时前
剑灵服务端源码(c#版本+数据库+配套客户端+服务端)
游戏·c#·游戏程序·游戏策划
下一秒_待续11 小时前
C# 使用Socket通信,新建WinForm服务端、客户端程序
websocket·c#·socket·winforms
wo637043111 小时前
[Visual Stuidio 2022使用技巧]2.配置及常用快捷键
c#·.net·wpf
IOT.FIVE.NO.112 小时前
C#笔记10 Thread类怎么终止(Abort)和阻止(Join)线程
linux·开发语言·学习·c#
萨达大13 小时前
C# USB通信技术(通过LibUsbDotNet库)
c#·usb·libusb
看山还是山,看水还是。13 小时前
鸿蒙OS 线程间通信
android·java·开发语言·笔记·华为·c#·harmonyos
__water13 小时前
『功能项目』调整Boss技能bug【51】
c#·bug·unity引擎