c#中的数组进阶

发布于:2024-07-27 ⋅ 阅读:(34) ⋅ 点赞:(0)

C#中数组的只读属性

在C#中,数组本身是引用类型,但你可以通过使用 Array 类的 ReadOnly 属性来创建一个只读的数组视图。这不会改变原始数组的可写性,但会返回一个新的 Array 对象,其 IsReadOnly 属性为 true,这意味着你不能修改这个数组视图的元素。

以下是如何使用 Array.ReadOnly 方法创建一个只读数组的示例:

using System;
​
public class Program
{
    public static void Main()
    {
        int[] originalArray = { 1, 2, 3, 4, 5 };
        Array readOnlyArray = Array.ReadOnly(originalArray);
​
        // 尝试修改只读数组将导致编译错误
        // readOnlyArray[0] = 10; // 错误:无法对只读数组赋值
​
        // 打印只读数组的元素
        foreach (int item in readOnlyArray)
        {
            Console.WriteLine(item);
        }
​
        // 检查数组是否只读
        Console.WriteLine("Is the array read-only? " + readOnlyArray.IsReadOnly);
    }
}

在上面的代码中,originalArray 是一个普通的可变数组。通过调用 Array.ReadOnly(originalArray),我们创建了一个只读视图 readOnlyArray。尝试修改 readOnlyArray 的元素将导致编译错误,因为 readOnlyArray.IsReadOnly 返回 true

只读数组视图的 IsReadOnly 属性虽然为 true,但这并不阻止你通过原始数组修改数据,因为只读视图仅仅是一个视图,它指向的是同一个底层数组。如果你需要确保数组在逻辑上也是不可变的,你可能需要考虑使用不可变集合类

使用 Array.ReadOnly 方法可以作为保护数组不被意外修改的一种方式,尤其是在将数组传递给可能修改它的外部方法时。

注意: 只读属性的数组可以在类的构造函数中通过new进行修改

dynamic和var的区别(面试会问)

var

  • var 是一个类型推断关键字,它允许编译器根据变量的初始化表达式推断出变量的类型。

  • var 仅在编译时使用,编译器会根据变量的初始化值确定其类型,并在编译时进行类型检查。

  • var 可以用于任何类型的变量,但一旦类型被推断出来,它就和显式声明的类型一样,具有类型安全。

dynamic

  • dynamic 是一个特殊的类型,它在运行时解析,而不是在编译时。

  • 使用 dynamic 类型的变量可以调用方法、访问属性或调用索引器,而不需要编译器在编译时知道对象的类型。

  • dynamic 类型的变量在运行时会进行类型检查,这意味着你可能会在运行时遇到类型错误,而不是在编译时。

  • dynamic 类型通常用于与动态语言交互(如调用COM对象或使用JavaScript引擎)或在编译时类型不明确的情况下。

主要区别:

  • 类型检查时机

    • var 在编译时进行类型检查,而 dynamic 在运行时进行类型检查。

  • 类型安全

    • var 提供类型安全,编译器会检查类型错误。

    • dynamic 不提供类型安全,类型错误会在运行时被检测到。

  • 用途

    • var 适用于简单的类型推断,减少代码量。

    • dynamic 适用于需要在运行时确定类型或与动态语言交互的场景。

  • 性能

    • var 通常具有更好的性能,因为它在编译时就确定了类型。

    • dynamic 可能会有性能开销,因为它需要在运行时解析类型。

  • 可读性

    • var 使得代码更简洁,但有时可能会降低代码的可读性,特别是在复杂的类型推断中。

    • dynamic 使得代码更灵活,但可能会增加代码的复杂性和可读性问题。

C#中数组的方法sort重写排序方法

在C#中,数组的 Sort 方法是静态方法,定义Array 类中,因此它不能被重写。但是,你可以使用 IComparerIComparer<T> 接口来自定义排序逻辑

using System;using System.Collections.Generic;

public class Person{ public string Name { get; set; } public int Age { get; set; }}

public class PersonComparer : IComparer<Person>{ public int Compare(Person x, Person y) { // 根据年龄排序 return x.Age.CompareTo(y.Age); }}

public class Program{ public static void Main() { Person[] people = new Person[] { new Person { Name = "Alice", Age = 30 }, new Person { Name = "Bob", Age = 25 }, new Person { Name = "Charlie", Age = 35 } };

// 使用自定义的比较器来排序数组 Array.Sort(people, new PersonComparer());

// 打印排序后的数组 foreach (var person in people) { Console.WriteLine($"{person.Name}, {person.Age}"); } }}

在这个示例中,我们定义了一个 Person 类,它有两个属性:NameAge。我们还定义了一个 PersonComparer 类,它实现了 IComparer<Person> 接口,并在 Compare 方法中定义了按年龄排序的逻辑。

这将使用一个匿名的 IComparer<Person> 实现,它根据年龄进行比较。

请注意,Array.Sort 是一个就地排序方法,它将直接修改原始数组。如果你不想修改原始数组,可以使用 Array.Sort 的泛型重载,它接受一个数组和一个比较器,并返回一个新的排序后的数组:

以下方法不会对原数组进行修改

Person[] sortedPeople = Array.Sort(people, new PersonComparer());

这将返回一个新的数组,原始数组 people 保持不变。

在C#中,运行时编译的变量

1.动态类型(dynamic)dynamic 类型在运行时解析,这意味着编译器不会对 dynamic 类型的变量进行类型检查。所有的类型检查都是在运行时执行的,这使得你可以调用方法或访问属性而不需要知道对象的确切类型。

2.反射(Reflection):使用反射,你可以在运行时获取类型的信息,创建类型的实例,调用方法,访问字段等。反射通常用于需要在运行时决定如何操作对象的场景。

3.表达式树(Expression Trees):表达式树是一种在编译时构建的,用于在运行时执行的代码表示。它们可以被用来生成动态查询,或者在运行时编译和执行。

4.CodeDOM:Code Document Object Model (CodeDOM) 是一个在.NET中用于表示源代码的类库。你可以使用CodeDOM来生成源代码,然后编译这个源代码为可执行的程序集。

5.Roslyn API:Roslyn 是.NET Compiler Platform的简称,它提供了编译器API,允许开发者读取、分析和修改C#和Visual Basic代码。你可以使用Roslyn在运行时修改和编译代码。

6.C#脚本:C#脚本允许开发者编写和执行C#脚本代码,这些脚本可以在运行时被加载和执行。


网站公告

今日签到

点亮在社区的每一天
去签到