C#数组与字符串算法实战:22个核心技巧精解

数组和字符串操作是C#开发者的基本功,也是面试和实际项目中的高频考点。本文将带你系统掌握从基础遍历到高级算法的22个核心技巧,每个案例都配有可运行的代码示例和工程应用场景分析。

1. 基础操作与数学计算

1.1 数组元素聚合运算

数组求和、求积和平均值是最基础的操作,但在实际项目中经常用于数据统计。下面是一个优化的聚合运算实现:

public static class ArrayOperations
{
    public static int Sum(int[] arr) => arr.Aggregate(0, (acc, x) => acc + x);
    
    public static long Product(int[] arr) => 
        arr.Aggregate(1L, (acc, x) => acc * x);
    
    public static double Average(int[] arr) => 
        arr.Length == 0 ? 0 : (double)Sum(arr) / arr.Length;
}

工程应用:电商平台计算订单总金额、商品平均评分等场景。

1.2 极值查找与条件筛选

查找数组中的极值和满足条件的元素是常见需求:

public static (int min, int max) FindMinMax(int[] arr)
{
    if (arr == null || arr.Length == 0)
        throw new ArgumentException("数组不能为空");
    
    int min = arr[0], max = arr[0];
    for (int i = 1; i < arr.Length; i++)
    {
        min = Math.Min(min, arr[i]);
        max = Math.Max(max, arr[i]);
    }
    return (min, max);
}

public static int[] FilterEvens(int[] arr) => 
    arr.Where(x => x % 2 == 0).ToArray();

提示:使用LINQ可以简化代码,但在性能关键场景建议使用原生循环

2. 数组与字符串变换

2.1 反转操作的艺术

数组和字符串反转有多种实现方式,各有适用场景:

方法时间复杂度空间复杂度适用场景
Array.ReverseO(n)O(1)简单反转
双指针法O(n)O(1)原地修改
LINQ ReverseO(n)O(n)需要新对象
// 双指针反转数组
public static void ReverseArray(int[] arr)
{
    for (int i = 0, j = arr.Length - 1; i < j; i++, j--)
    {
        (arr[i], arr[j]) = (arr[j], arr[i]);
    }
}

// 字符串反转扩展方法
public static string Reverse(this string s) =>
    string.Concat(s.Reverse());

2.2 回文检测优化技巧

回文检测需要考虑大小写和标点符号:

public static bool IsPalindrome(string s)
{
    s = new string(s.Where(char.IsLetterOrDigit).ToArray())
        .ToLowerInvariant();
    return s == s.Reverse();
}

性能优化:对于超长字符串,可以提前终止比较:

for (int i = 0; i < s.Length / 2; i++)
{
    if (s[i] != s[s.Length - 1 - i])
        return false;
}
return true;

3. 算法思维训练

3.1 两数之和的多种解法

给定数组和目标值,找出两数之和等于目标值的索引:

// 暴力解法 O(n²)
public static (int, int) TwoSumBruteForce(int[] nums, int target)
{
    for (int i = 0; i < nums.Length; i++)
        for (int j = i + 1; j < nums.Length; j++)
            if (nums[i] + nums[j] == target)
                return (i, j);
    throw new Exception("No solution");
}

// 哈希表优化 O(n)
public static (int, int) TwoSumOptimized(int[] nums, int target)
{
    var dict = new Dictionary<int, int>();
    for (int i = 0; i < nums.Length; i++)
    {
        int complement = target - nums[i];
        if (dict.TryGetValue(complement, out int index))
            return (index, i);
        dict[nums[i]] = i;
    }
    throw new Exception("No solution");
}

3.2 滑动窗口算法精要

滑动窗口是处理子串/子数组问题的利器,典型应用如求最长无重复字符子串:

public static int LongestUniqueSubstring(string s)
{
    var lastIndex = new Dictionary<char, int>();
    int maxLen = 0, start = 0;
    
    for (int end = 0; end < s.Length; end++)
    {
        if (lastIndex.TryGetValue(s[end], out int index))
            start = Math.Max(start, index + 1);
        
        lastIndex[s[end]] = end;
        maxLen = Math.Max(maxLen, end - start + 1);
    }
    return maxLen;
}

窗口模板

  1. 初始化左右指针
  2. 移动右指针扩展窗口
  3. 满足条件时移动左指针收缩窗口
  4. 更新结果

4. 高级数据结构应用

4.1 矩阵旋转的位运算优化

N×N矩阵顺时针旋转90度的最优解:

public static void RotateMatrix(int[,] matrix)
{
    int n = matrix.GetLength(0);
    for (int layer = 0; layer < n / 2; layer++)
    {
        int first = layer;
        int last = n - 1 - layer;
        for (int i = first; i < last; i++)
        {
            int offset = i - first;
            int top = matrix[first, i];
            // 左→上
            matrix[first, i] = matrix[last-offset, first];
            // 下→左
            matrix[last-offset, first] = matrix[last, last-offset];
            // 右→下
            matrix[last, last-offset] = matrix[i, last];
            // 上→右
            matrix[i, last] = top;
        }
    }
}

4.2 栈的经典应用:括号匹配

使用栈检查括号序列有效性:

public static bool IsValidParentheses(string s)
{
    var stack = new Stack<char>();
    var pairs = new Dictionary<char, char>
    {
        [')'] = '(', 
        [']'] = '[', 
        ['}'] = '{'
    };
    
    foreach (char c in s)
    {
        if (pairs.ContainsValue(c))
            stack.Push(c);
        else if (stack.Count == 0 || stack.Pop() != pairs[c])
            return false;
    }
    return stack.Count == 0;
}

变体问题:计算最长有效括号子串长度:

public static int LongestValidParentheses(string s)
{
    var stack = new Stack<int>();
    stack.Push(-1);
    int max = 0;
    
    for (int i = 0; i < s.Length; i++)
    {
        if (s[i] == '(')
            stack.Push(i);
        else
        {
            stack.Pop();
            if (stack.Count == 0)
                stack.Push(i);
            else
                max = Math.Max(max, i - stack.Peek());
        }
    }
    return max;
}

5. 字符串处理进阶

5.1 字符串压缩算法对比

不同压缩算法的实现与选择:

// 基础压缩
public static string CompressBasic(string s)
{
    if (string.IsNullOrEmpty(s)) return s;
    
    var sb = new StringBuilder();
    int count = 1;
    for (int i = 1; i <= s.Length; i++)
    {
        if (i < s.Length && s[i] == s[i-1])
            count++;
        else
        {
            sb.Append(s[i-1]).Append(count);
            count = 1;
        }
    }
    return sb.Length < s.Length ? sb.ToString() : s;
}

// 优化版(仅存储字符)
public static string CompressOptimized(string s)
{
    var sb = new StringBuilder();
    int count = 0;
    for (int i = 0; i < s.Length; i++)
    {
        count++;
        if (i == s.Length - 1 || s[i] != s[i+1])
        {
            sb.Append(s[i]);
            if (count > 1) sb.Append(count);
            count = 0;
        }
    }
    return sb.ToString();
}

5.2 最长公共前缀的二分查找解法

传统解法与优化解法的对比:

// 水平扫描法
public static string LongestCommonPrefix(string[] strs)
{
    if (strs.Length == 0) return "";
    
    string prefix = strs[0];
    for (int i = 1; i < strs.Length; i++)
    {
        while (strs[i].IndexOf(prefix) != 0)
        {
            prefix = prefix[..^1];
            if (string.IsNullOrEmpty(prefix)) return "";
        }
    }
    return prefix;
}

// 二分查找优化
public static string LongestCommonPrefixBinary(string[] strs)
{
    if (strs.Length == 0) return "";
    
    int minLen = strs.Min(s => s.Length);
    int low = 1, high = minLen;
    
    while (low <= high)
    {
        int mid = (low + high) / 2;
        if (IsCommonPrefix(strs, mid))
            low = mid + 1;
        else
            high = mid - 1;
    }
    return strs[0][..((low + high) / 2)];
}

private static bool IsCommonPrefix(string[] strs, int len)
{
    string prefix = strs[0][..len];
    return strs.All(s => s.StartsWith(prefix));
}

6. 实战技巧与性能优化

6.1 避免装箱拆箱

值类型操作中的性能陷阱:

// 不好的写法(有装箱)
ArrayList list = new ArrayList();
list.Add(1);  // 装箱
int num = (int)list[0];  // 拆箱

// 优化写法(使用泛型)
List<int> genericList = new List<int>();
genericList.Add(1);  // 无装箱
int num = genericList[0];  // 无拆箱

6.2 字符串拼接优化

不同拼接方式的性能对比(单位:毫秒):

方法100次1000次10000次
+操作符0.123.45280.5
StringBuilder0.080.151.2
string.Concat0.050.325.4
// 推荐写法
var sb = new StringBuilder();
for (int i = 0; i < 10000; i++)
    sb.Append(i.ToString());
string result = sb.ToString();

6.3 数组与集合的选择

不同数据结构的特性对比:

结构随机访问插入删除内存使用适用场景
数组O(1)O(n)紧凑固定大小数据
ListO(1)O(n)动态频繁增删
LinkedListO(n)O(1)较高频繁插入删除
// 预分配数组大小
int[] arr = new int[100]; 

// 动态扩容List
var list = new List<int>(100);  // 建议设置初始容量

7. 工程实践与异常处理

7.1 防御性编程实践

健壮的数组操作需要考虑各种边界条件:

public static int SafeArrayAccess(int[] arr, int index)
{
    if (arr == null)
        throw new ArgumentNullException(nameof(arr));
    if (index < 0 || index >= arr.Length)
        throw new IndexOutOfRangeException(
            $"Index {index} out of range [0, {arr.Length - 1}]");
    return arr[index];
}

7.2 自定义异常设计

为特定业务场景创建专属异常:

public class InvalidArrayOperationException : Exception
{
    public int ErrorCode { get; }
    public string Operation { get; }
    
    public InvalidArrayOperationException(
        string message, int code, string operation) 
        : base(message)
    {
        ErrorCode = code;
        Operation = operation;
    }
}

// 使用示例
throw new InvalidArrayOperationException(
    "Array size mismatch", 1001, "Matrix multiplication");

8. 单元测试与调试技巧

8.1 为数组算法编写测试

使用xUnit测试框架示例:

public class ArrayTests
{
    [Theory]
    [InlineData(new[] {1,2,3}, 6)]
    [InlineData(new[] {5}, 5)]
    [InlineData(new int[0], 0)]
    public void SumArray_ShouldReturnCorrectSum(int[] input, int expected)
    {
        int actual = ArrayOperations.Sum(input);
        Assert.Equal(expected, actual);
    }
    
    [Fact]
    public void ReverseArray_ShouldHandleNull()
    {
        int[] arr = null;
        Assert.Throws<ArgumentNullException>(() => ArrayOperations.Reverse(arr));
    }
}

8.2 调试复杂算法的技巧

使用Visual Studio调试器的进阶功能:

  1. 条件断点:右键断点→条件
  2. 数据断点:调试→窗口→断点→新建数据断点
  3. 即时窗口:调试时输入表达式求值
  4. 内存窗口:查看数组内存布局
// 调试示例:观察滑动窗口变化
var window = new List<int>();
for (int i = 0; i < nums.Length; i++)
{
    // 在此处设置条件断点:i > 3
    window.Add(nums[i]);
    if (window.Count > k)
        window.RemoveAt(0);
}

9. 性能分析与优化

9.1 基准测试工具使用

使用BenchmarkDotNet进行性能测试:

[MemoryDiagnoser]
public class AlgorithmBenchmarks
{
    private readonly int[] data = Enumerable.Range(1, 1000).ToArray();
    
    [Benchmark]
    public int LinqSum() => data.Sum();
    
    [Benchmark]
    public int ManualSum()
    {
        int sum = 0;
        foreach (int num in data) sum += num;
        return sum;
    }
}

// 输出结果:
// |    Method |     Mean |    Error |   StdDev | Allocated |
// |---------- |---------:|---------:|---------:|----------:|
// |   LinqSum | 1.234 us | 0.0234 us | 0.0207 us |      32 B |
// | ManualSum | 0.543 us | 0.0102 us | 0.0096 us |         - |

9.2 算法复杂度实战分析

常见算法的时间复杂度对比:

// O(1) - 常数时间
int GetFirst(int[] arr) => arr[0];

// O(log n) - 二分查找
int BinarySearch(int[] arr, int target)
{
    int left = 0, right = arr.Length - 1;
    while (left <= right)
    {
        int mid = left + (right - left) / 2;
        if (arr[mid] == target) return mid;
        if (arr[mid] < target) left = mid + 1;
        else right = mid - 1;
    }
    return -1;
}

// O(n²) - 冒泡排序
void BubbleSort(int[] arr)
{
    for (int i = 0; i < arr.Length - 1; i++)
        for (int j = 0; j < arr.Length - i - 1; j++)
            if (arr[j] > arr[j + 1])
                (arr[j], arr[j + 1]) = (arr[j + 1], arr[j]);
}

10. 跨语言对比与选择

10.1 C#与Python数组操作对比

相同算法的不同语言实现差异:

# Python实现两数之和
def two_sum(nums, target):
    seen = {}
    for i, num in enumerate(nums):
        complement = target - num
        if complement in seen:
            return (seen[complement], i)
        seen[num] = i
    return None

关键区别

  • Python使用字典而非泛型Dictionary
  • 没有类型声明,更简洁但缺乏类型安全
  • enumerate替代C#的for循环索引

10.2 何时选择C#处理数组

适合使用C#的场景:

  1. 需要强类型检查和编译时验证
  2. 处理大型数值数据集(性能优势)
  3. 与.NET生态集成(如ASP.NET、Entity Framework)
  4. 需要多线程处理的场景(Task Parallel Library)

11. 设计模式应用

11.1 策略模式实现多种排序

将排序算法封装为可互换的策略:

public interface ISortStrategy
{
    void Sort(int[] arr);
}

public class BubbleSort : ISortStrategy { /* 实现 */ }
public class QuickSort : ISortStrategy { /* 实现 */ }

public class ArraySorter
{
    private ISortStrategy _strategy;
    
    public ArraySorter(ISortStrategy strategy) => _strategy = strategy;
    
    public void SetStrategy(ISortStrategy strategy) => _strategy = strategy;
    
    public void Sort(int[] arr) => _strategy.Sort(arr);
}

// 使用
var sorter = new ArraySorter(new BubbleSort());
sorter.Sort(data);
sorter.SetStrategy(new QuickSort());
sorter.Sort(data);

11.2 迭代器模式处理多维数组

实现自定义的数组遍历方式:

public class MatrixIterator : IEnumerable<int>
{
    private readonly int[,] _matrix;
    
    public MatrixIterator(int[,] matrix) => _matrix = matrix;
    
    public IEnumerator<int> GetEnumerator()
    {
        for (int i = 0; i < _matrix.GetLength(0); i++)
            for (int j = 0; j < _matrix.GetLength(1); j++)
                yield return _matrix[i, j];
    }
    
    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}

// 使用
var matrix = new int[3,3] { {1,2,3}, {4,5,6}, {7,8,9} };
foreach (int num in new MatrixIterator(matrix))
    Console.WriteLine(num);

12. 并发与并行处理

12.1 并行数组操作

使用Parallel类加速数组处理:

public static void ParallelArrayOperations(int[] arr)
{
    // 并行初始化数组
    Parallel.For(0, arr.Length, i => arr[i] = i * 2);
    
    // 并行求和
    long sum = 0;
    Parallel.ForEach(arr, num => Interlocked.Add(ref sum, num));
    
    // 并行转换
    Parallel.For(0, arr.Length, i => arr[i] = (int)Math.Sqrt(arr[i]));
}

注意:并行操作适合CPU密集型任务,对于简单操作可能因线程开销反而变慢

12.2 线程安全集合使用

并发环境下的集合选择:

// 线程安全字典
var concurrentDict = new ConcurrentDictionary<int, string>();
Parallel.For(0, 100, i => concurrentDict[i] = i.ToString());

// 阻塞集合
var blockingCollection = new BlockingCollection<int>();
Task.Run(() => 
{
    foreach (var item in blockingCollection.GetConsumingEnumerable())
        Console.WriteLine(item);
});

Parallel.For(0, 100, i => blockingCollection.Add(i));
blockingCollection.CompleteAdding();

13. 内存优化技巧

13.1 ArrayPool减少GC压力

使用数组池重用数组内存:

var pool = ArrayPool<int>.Shared;
int[] array = pool.Rent(1024);  // 从池中获取数组
try
{
    // 使用array...
    for (int i = 0; i < array.Length; i++)
        array[i] = i;
}
finally
{
    pool.Return(array);  // 归还到池中
}

13.2 Span高效内存访问

使用Span减少内存分配:

int[] arr = { 1, 2, 3, 4, 5 };
Span<int> span = arr.AsSpan();

// 切片操作不分配新数组
Span<int> slice = span.Slice(1, 3); 

// 栈上分配
Span<int> stackSpan = stackalloc int[10];
for (int i = 0; i < stackSpan.Length; i++)
    stackSpan[i] = i;

14. 实际项目案例

14.1 电商价格分析系统

典型数组操作场景:

public class PriceAnalyzer
{
    public (decimal min, decimal max, decimal avg) AnalyzePrices(decimal[] prices)
    {
        if (prices == null || prices.Length == 0)
            throw new ArgumentException("价格数据不能为空");
            
        decimal min = prices[0], max = prices[0], sum = 0;
        foreach (var price in prices)
        {
            min = Math.Min(min, price);
            max = Math.Max(max, price);
            sum += price;
        }
        return (min, max, sum / prices.Length);
    }
    
    public int[] FindPromotionDays(decimal[] dailySales, decimal threshold)
    {
        var days = new List<int>();
        for (int i = 0; i < dailySales.Length; i++)
            if (dailySales[i] > threshold)
                days.Add(i + 1);  // 第几天
        return days.ToArray();
    }
}

14.2 游戏开发中的数组应用

游戏状态管理示例:

public class GameBoard
{
    private readonly int[,] _cells;
    private readonly int _size;
    
    public GameBoard(int size)
    {
        _size = size;
        _cells = new int[size, size];
    }
    
    public void Randomize()
    {
        var rnd = new Random();
        for (int i = 0; i < _size; i++)
            for (int j = 0; j < _size; j++)
                _cells[i, j] = rnd.Next(0, 2);  // 0或1
    }
    
    public int CountAliveNeighbors(int x, int y)
    {
        int count = 0;
        for (int i = Math.Max(0, x-1); i <= Math.Min(_size-1, x+1); i++)
            for (int j = Math.Max(0, y-1); j <= Math.Min(_size-1, y+1); j++)
                if (!(i == x && j == y) && _cells[i, j] == 1)
                    count++;
        return count;
    }
}

15. 前沿技术展望

15.1 SIMD指令加速数组运算

使用System.Numerics进行向量化计算:

public static unsafe float SimdSum(float[] arr)
{
    int vectorSize = Vector<float>.Count;
    var accVector = Vector<float>.Zero;
    int i = 0;
    
    // 向量化部分
    for (; i <= arr.Length - vectorSize; i += vectorSize)
    {
        var v = new Vector<float>(arr, i);
        accVector += v;
    }
    
    // 剩余部分
    float result = 0;
    for (; i < arr.Length; i++)
        result += arr[i];
    
    // 累加向量中的元素
    for (int j = 0; j < vectorSize; j++)
        result += accVector[j];
    
    return result;
}

15.2 机器学习中的数组应用

使用ML.NET处理数据:

var data = new List<InputData>();
// 填充数据...

var context = new MLContext();
var pipeline = context.Transforms
    .Concatenate("Features", nameof(InputData.Features))
    .Append(context.Regression.Trainers.Sdca(
        labelColumnName: nameof(InputData.Label)));
    
var model = pipeline.Fit(context.Data.LoadFromEnumerable(data));

16. 调试与问题排查

16.1 常见数组越界问题

典型错误模式及修复:

// 错误写法
for (int i = 0; i <= arr.Length; i++)  // 应该使用 < 而不是 <=
    Console.WriteLine(arr[i]);

// 正确写法
for (int i = 0; i < arr.Length; i++)
    Console.WriteLine(arr[i]);

// 多维数组错误
int[,] matrix = new int[3,3];
for (int i = 0; i <= matrix.GetLength(0); i++)  // 错误
    for (int j = 0; j <= matrix.GetLength(1); j++)  // 错误
        matrix[i,j] = i + j;

16.2 性能问题诊断

使用Stopwatch分析代码:

var sw = new Stopwatch();
sw.Start();

// 测试代码
var arr = new int[1000000];
for (int i = 0; i < arr.Length; i++)
    arr[i] = i * 2;

sw.Stop();
Console.WriteLine($"耗时: {sw.ElapsedMilliseconds}ms");

17. 编码规范与最佳实践

17.1 数组命名与使用准则

规范类型不良实践推荐实践
命名int[] aint[] studentScores
初始化int[] arr;int[] arr = new int[10];
长度检查if(arr != null)if(arr?.Length > 0)
遍历for(int i=0;i<10;i++)foreach(var item in arr)

17.2 异常处理原则

健壮的数组操作异常处理:

public void ProcessArray(int[] arr)
{
    try
    {
        if (arr == null) throw new ArgumentNullException(nameof(arr));
        if (arr.Length == 0) throw new ArgumentException("数组不能为空");
        
        // 业务逻辑...
    }
    catch (IndexOutOfRangeException ex)
    {
        Console.WriteLine($"数组越界: {ex.Message}");
        throw;  // 重新抛出
    }
    catch (Exception ex)
    {
        Console.WriteLine($"处理失败: {ex.Message}");
        throw new ArrayProcessingException("处理失败", ex);
    }
}

18. 扩展方法与LINQ技巧

18.1 有用的数组扩展方法

创建自定义扩展方法:

public static class ArrayExtensions
{
    public static void Shuffle<T>(this T[] array)
    {
        var rng = new Random();
        int n = array.Length;
        while (n > 1)
        {
            int k = rng.Next(n--);
            (array[n], array[k]) = (array[k], array[n]);
        }
    }
    
    public static T[] Slice<T>(this T[] source, int start, int length)
    {
        var slice = new T[length];
        Array.Copy(source, start, slice, 0, length);
        return slice;
    }
}

// 使用
var numbers = Enumerable.Range(1, 10).ToArray();
numbers.Shuffle();
var subArray = numbers.Slice(2, 5);

18.2 LINQ高级查询技巧

复杂数组查询示例:

var salesData = new[]
{
    new { Month = "Jan", Amount = 1000 },
    new { Month = "Feb", Amount = 1500 },
    // ...
};

// 多条件分组
var query = salesData
    .GroupBy(s => s.Amount > 1200 ? "High" : "Low")
    .Select(g => new { Category = g.Key, Total = g.Sum(x => x.Amount) });
    
// 滑动窗口平均值
int windowSize = 3;
var movingAvg = Enumerable.Range(0, salesData.Length - windowSize + 1)
    .Select(i => salesData
        .Skip(i)
        .Take(windowSize)
        .Average(x => x.Amount));

19. 跨平台注意事项

19.1 不同运行时中的数组差异

.NET Framework vs .NET Core差异:

特性.NET Framework.NET Core
默认数组大小上限2GB取决于系统
Array.Sort算法快速排序内省排序
空数组处理可能返回null总是返回空数组

19.2 序列化兼容性问题

JSON序列化时的数组处理:

var arr = new int[] { 1, 2, 3 };

// System.Text.Json (推荐)
string json = JsonSerializer.Serialize(arr);
int[] deserialized = JsonSerializer.Deserialize<int[]>(json);

// Newtonsoft.Json (旧项目)
string json = JsonConvert.SerializeObject(arr);
int[] deserialized = JsonConvert.DeserializeObject<int[]>(json);

20. 可视化与调试辅助

20.1 数组内容可视化输出

创建友好的数组显示格式:

public static string ToMatrixString<T>(this T[,] matrix, string delimiter = "\t")
{
    var sb = new StringBuilder();
    for (int i = 0; i < matrix.GetLength(0); i++)
    {
        for (int j = 0; j < matrix.GetLength(1); j++)
            sb.Append(matrix[i, j]).Append(delimiter);
        sb.AppendLine();
    }
    return sb.ToString();
}

// 使用
var matrix = new int[3,3] { {1,2,3}, {4,5,6}, {7,8,9} };
Console.WriteLine(matrix.ToMatrixString());

20.2 调试时查看复杂结构

使用DebuggerDisplay特性:

[DebuggerDisplay("Count = {Count}")]
public class CustomArray<T>
{
    private readonly T[] _items;
    
    public CustomArray(int size) => _items = new T[size];
    
    public int Count => _items.Length;
    
    [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
    public T[] Items => _items;
}

21. 安全编码实践

21.1 输入验证模式

安全的数组处理方法:

public static void ProcessUserInput(int[] userInput)
{
    // 验证null
    if (userInput == null)
        throw new ArgumentNullException(nameof(userInput));
    
    // 验证大小
    const int maxSize = 1000;
    if (userInput.Length > maxSize)
        throw new ArgumentException($"输入数组不能超过{maxSize}个元素");
    
    // 验证内容
    for (int i = 0; i < userInput.Length; i++)
    {
        if (userInput[i] < 0)
            throw new ArgumentException($"第{i}个元素不能为负数");
    }
    
    // 安全处理...
}

21.2 防止缓冲区溢出

安全复制数组的方法:

public static void SafeCopy(int[] source, int[] destination)
{
    if (source == null || destination == null)
        throw new ArgumentNullException();
    
    // 计算实际可复制的长度
    int length = Math.Min(source.Length, destination.Length);
    if (length == 0) return;
    
    Array.Copy(source, destination, length);
}

22. 性能关键代码优化

22.1 避免边界检查

使用unsafe代码提升性能:

public static unsafe int UnsafeSum(int[] arr)
{
    int sum = 0;
    fixed (int* ptr = arr)
    {
        for (int i = 0; i < arr.Length; i++)
            sum += ptr[i];  // 不进行边界检查
    }
    return sum;
}

警告:unsafe代码需要特别小心,仅用于性能关键路径

22.2 内存局部性优化

优化数据访问模式:

// 不好的访问模式(列优先)
for (int j = 0; j < cols; j++)
    for (int i = 0; i < rows; i++)
        matrix[i, j] = ComputeValue();

// 好的访问模式(行优先)
for (int i = 0; i < rows; i++)
    for (int j = 0; j < cols; j++)
        matrix[i, j] = ComputeValue();

原理:现代CPU缓存对顺序访问更友好

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐