C# Lambda 闭包常见误区:99%开发者都忽略的5个关键细节

C#线程底层原理:从Thread类深入CLR并发模型 线程是.NET并发编程的基石概念,其本质是操作系统内核线程在CLR中的托管封装。理解Thread类的创建、调度、状态流转与栈管理,是掌握Task、async/await和ThreadPool等高层抽象的前提。它涉及Windows线程优先级映射、虚拟内存分配、同步上下文绑定及文化信息隔离等核心机制。这些底层行为直接决定应用在高并发、I/O密集或CPU密集场景下的稳定性与性能表现,如线程饥饿、死锁、TLS污染和文化格式错乱等问题。本文聚焦System.Threading.Thread原语,结合.NET Fram 阅读详情

第一章:C# Lambda 闭包的本质与常见误解

Lambda 表达式在 C# 中被广泛用于简化委托的定义,而当其捕获外部变量时,便形成了“闭包”。C# 的闭包机制通过编译器自动生成类来保存被捕获的变量,使得这些变量的生命周期得以延长,超出其原始作用域。

闭包的工作机制

当 Lambda 表达式引用了局部变量时,C# 编译器会创建一个匿名类来“捕获”该变量。这个变量不再存储在栈上,而是作为该类的字段存在,从而避免在方法执行结束后被销毁。
// 示例:Lambda 闭包捕获局部变量
int multiplier = 10;
Func multiply = x => x * multiplier;

// multiplier 被闭包捕获,即使在外层方法结束前仍可访问
Console.WriteLine(multiply(5)); // 输出 50
上述代码中,multiplier 被 Lambda 捕获,编译器生成一个包含 multiplier 字段的类,并将 Lambda 编译为该类中的方法。

常见的误解

  • 误认为闭包是实时复制变量:实际上闭包捕获的是变量的引用,而非值。若在循环中使用 Lambda 捕获循环变量,可能引发意外结果。
  • 忽略变量共享问题:多个 Lambda 可能共享同一个捕获变量,修改其中一个会影响其他。
场景行为
捕获局部变量变量提升至编译器生成的类中
循环中捕获 i所有 Lambda 共享最终的 i 值(C# 5 前)
graph LR A[Lambda表达式] -- 捕获 --> B[局部变量] B --> C[编译器生成的类] C --> D[堆上存储变量] D --> E[延长生命周期]

第二章:变量捕获的深层机制

2.1 变量引用而非值复制:理解闭包中的变量生命周期

在 JavaScript 等支持闭包的语言中,函数会捕获其词法作用域中的变量**引用**,而非创建值的副本。这意味着内部函数始终访问的是外部变量的当前状态。
闭包中的变量绑定机制

function createCounter() {
    let count = 0;
    return function() {
        return ++count;
    };
}
const counter = createCounter();
console.log(counter()); // 1
console.log(counter()); // 2
上述代码中,count 被闭包引用并持久化在内存中。即使 createCounter 执行完毕,count 也不会被回收。
变量生命周期的延伸
  • 普通局部变量在函数退出后销毁;
  • 被闭包引用的变量生命周期延长至最后一个引用消失;
  • 多个闭包共享同一变量时,修改会相互影响。

2.2 循环中的陷阱:for循环与foreach中Lambda的不同行为

在C#等支持Lambda表达式的语言中,开发者常忽略for循环与foreach循环在捕获循环变量时的差异。
问题重现

for (int i = 0; i < 3; i++)
{
    Task.Run(() => Console.Write(i));
}
上述代码可能输出“333”,因为所有Lambda共享同一个变量i,当任务执行时,i已变为3。 而使用foreach:

var list = new List<int>{1,2,3};
foreach (var item in list)
{
    Task.Run(() => Console.Write(item));
}
输出结果为“123”,因为在C# 5.0及以上版本中,每次迭代都会创建独立的item副本。
本质原因
  • for循环变量作用域在整个循环外部,被所有委托共享
  • foreach在每次迭代时生成新的变量实例(闭包捕获机制不同)
正确做法是在循环内部创建局部副本:

for (int i = 0; i < 3; i++)
{
    int local = i;
    Task.Run(() => Console.Write(local));
}

2.3 捕获局部变量时的内存泄漏风险与规避策略

在闭包或异步任务中捕获局部变量时,若未正确管理引用关系,可能导致对象无法被垃圾回收,从而引发内存泄漏。
常见泄漏场景
当 lambda 表达式或内部类持有外部局部变量时,该变量会被复制或引用至堆内存。若这些引用长期存在(如注册为监听器),即使栈帧已退出,对象仍驻留内存。

List<Runnable> tasks = new ArrayList<>();
for (int i = 0; i < 10; i++) {
    tasks.add(() -> System.out.println("Value: " + i)); // 编译错误:i 非 effectively final
}
上述代码无法通过编译,因 i 不是有效终态。若将其改为数组或包装类型,则可能意外延长生命周期。
规避策略
  • 避免在闭包中捕获大对象或集合
  • 使用弱引用(WeakReference)持有外部对象
  • 及时清理注册的回调或监听器
策略适用场景效果
弱引用缓存、监听器允许GC回收
手动注销事件订阅主动释放引用

2.4 多线程环境下共享变量的并发访问问题

在多线程编程中,多个线程同时访问同一共享变量时,若缺乏同步机制,极易引发数据竞争(Race Condition),导致程序行为不可预测。
典型并发问题示例
以下Go语言代码演示了两个线程对共享变量 `counter` 的非原子操作:
var counter int

func worker() {
    for i := 0; i < 1000; i++ {
        counter++ // 非原子操作:读取、修改、写入
    }
}

// 启动两个协程
go worker()
go worker()
上述代码中,`counter++` 实际包含三个步骤:读取当前值、加1、写回内存。多个线程交叉执行时,可能覆盖彼此的写入结果,最终值小于预期的2000。
常见解决方案对比
机制特点适用场景
互斥锁(Mutex)确保临界区串行执行频繁写操作
原子操作无锁、高效简单类型增减

2.5 实践案例:修复典型的变量捕获错误代码

在闭包与循环结合的场景中,变量捕获错误尤为常见。JavaScript 中的 `var` 声明存在函数作用域问题,导致异步操作中捕获的是循环结束后的最终值。
问题代码示例

for (var i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 100);
}
// 输出:3, 3, 3(而非期望的 0, 1, 2)
该代码中,三个 `setTimeout` 回调均引用同一个变量 `i`,由于 `var` 缺乏块级作用域,循环结束后 `i` 的值为 3。
解决方案对比
  • 使用 let 替代 var,利用块级作用域隔离每次迭代
  • 通过 IIFE 创建独立闭包环境
修复后代码

for (let i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 100);
}
// 输出:0, 1, 2
let 在每次循环中创建新绑定,确保每个回调捕获独立的 `i` 值,从根本上解决变量共享问题。

第三章:作用域与延迟执行的隐式影响

3.1 延迟执行特性如何加剧闭包副作用

JavaScript 中的闭包结合延迟执行机制,常导致意料之外的副作用。当异步操作(如定时器或事件监听)引用外层变量时,闭包会保留对外部作用域的引用,而非值的副本。
典型问题场景

for (var i = 0; i < 3; i++) {
  setTimeout(() => {
    console.log(i); // 输出:3, 3, 3
  }, 100);
}
上述代码中,setTimeout 的回调函数形成闭包,共享同一个变量 i。由于 var 声明提升且无块级作用域,循环结束后 i 的值为 3,三个定时器均输出 3。
解决方案对比
  • 使用 let 创建块级作用域,使每次迭代独立绑定变量
  • 通过 IIFE 立即执行函数创建独立闭包环境
使用 let 改写后:

for (let i = 0; i < 3; i++) {
  setTimeout(() => {
    console.log(i); // 输出:0, 1, 2
  }, 100);
}
此时每次迭代生成新的词法绑定,闭包捕获的是当前作用域中的 i,避免了共享状态问题。

3.2 方法参数与闭包作用域的交互分析

在Go语言中,方法参数与闭包作用域之间的交互决定了变量捕获的方式和生命周期。当闭包引用外部方法的参数时,该参数会被捕获并延长其生命周期,即使原函数已返回。
值捕获与引用捕获的区别
闭包对外部变量的捕获分为值捕获和引用捕获。若捕获的是方法参数,通常为引用共享。
func counter(step int) func() int {
    return func() int {
        step += 1 // 捕获step参数,形成闭包
        return step
    }
}
上述代码中,step作为方法参数被闭包捕获,后续调用会持续修改其值。每次调用counter返回的新函数都持有独立的step副本。
变量生命周期的延伸
阶段变量状态
方法执行中参数位于栈帧
方法返回后因闭包引用逃逸至堆

3.3 实践案例:在LINQ查询中正确使用闭包逻辑

闭包在LINQ中的典型误用

在使用LINQ进行延迟执行时,若在循环中捕获循环变量,容易因闭包引用同一变量而产生意外结果。

var filters = new List>();
for (int i = 0; i < 3; i++)
{
    filters.Add(x => x == i); // 错误:所有委托引用同一个i
}
上述代码中,所有lambda表达式共享外部变量i的引用,最终值为3,导致过滤条件失效。

正确实现方式

应通过局部变量复制来隔离每次迭代的值:

var filters = new List>();
for (int i = 0; i < 3; i++)
{
    int local = i; // 创建局部副本
    filters.Add(x => x == local);
}
此时每个lambda捕获的是独立的local变量,确保闭包逻辑正确。
  • 延迟执行与变量生命周期需同步考虑
  • 闭包捕获的是变量而非值,注意引用一致性

第四章:性能与设计模式中的闭包应用权衡

4.1 闭包对委托分配和GC压力的影响

闭包在现代编程语言中广泛用于封装逻辑与上下文,但在频繁使用委托(delegate)的场景下,可能引发额外的内存分配,加剧垃圾回收(GC)压力。
闭包捕获导致的堆分配
当闭包捕获外部变量时,编译器会生成一个匿名类来持有这些变量,该实例位于堆上。每次调用都会分配新对象,增加GC负担。

for (int i = 0; i < 1000; i++)
{
    Action action = () => Console.WriteLine(i); // 捕获i,触发堆分配
    actions.Add(action);
}
上述代码中,循环内的 i 被每个闭包捕获,导致生成1000个独立的堆对象,显著增加短期GC频率。
优化策略对比
  • 避免在循环中创建捕获变量的闭包
  • 使用静态方法或预定义委托减少临时分配
  • 考虑使用 ref struct 或 Span<T> 减少堆依赖

4.2 避免过度依赖闭包提升代码可维护性

在复杂应用开发中,闭包常被用于封装私有状态和实现函数工厂,但过度使用可能导致内存泄漏与调试困难。
闭包的典型误用场景
function createHandlers(list) {
  const handlers = [];
  for (var i = 0; i < list.length; i++) {
    handlers.push(function() {
      console.log(i); // 所有函数共享同一个i,输出均为list.length
    });
  }
  return handlers;
}
上述代码因闭包捕获了外部变量 i,而 var 声明导致变量提升,最终所有处理器输出相同值。应使用 let 或立即执行函数修复作用域问题。
优化策略
  • 优先使用模块化设计替代闭包管理状态
  • 避免在循环中创建闭包,除非明确处理作用域绑定
  • 利用类或纯函数提升可测试性与可读性

4.3 使用静态函数替代简单闭包以优化性能

在高频调用的场景中,闭包虽灵活但可能带来额外的内存开销与执行损耗。每次创建闭包时,JavaScript 引擎需生成新的词法环境以捕获外部变量,而静态函数则无需此过程。
性能对比示例

// 闭包实现
function makeAdder(x) {
  return function(y) {
    return x + y;
  };
}
const add5 = makeAdder(5);

// 静态函数实现
function add5Static(y) {
  return 5 + y;
}
上述闭包版本每次调用 makeAdder 都会创建新作用域,而静态函数直接定义,避免了作用域链构建成本。
适用场景建议
  • 当逻辑不依赖外部状态时,优先使用静态函数
  • 在性能敏感路径(如循环、事件处理器)中避免不必要的闭包
  • 借助工具如 Chrome DevTools 分析函数调用开销

4.4 实践案例:重构高复杂度闭包为显式类结构

在处理状态管理复杂的闭包时,代码可读性与维护性显著下降。通过将其重构为显式类结构,可提升逻辑组织与测试便利性。
问题场景
以下闭包封装了计数器逻辑,但状态与行为耦合紧密:
function createCounter() {
  let count = 0;
  return {
    increment: () => ++count,
    decrement: () => --count,
    value: () => count
  };
}
该结构难以扩展权限控制或日志追踪等新需求。
重构为类结构
使用类显式暴露状态与行为:
class Counter {
  constructor() { this._count = 0; }
  increment() { this._count++; }
  decrement() { this._count--; }
  get value() { return this._count; }
}
类结构支持继承、私有字段和方法重写,便于添加审计功能。
优势对比
维度闭包实现类实现
可扩展性低高
可测试性中高

第五章:走出误区,写出更健壮的Lambda表达式

避免过度嵌套的Lambda表达式
过度嵌套的Lambda会导致代码可读性急剧下降。应将复杂逻辑提取为独立方法或函数式接口实现。
  • 嵌套超过两层时,考虑重构为私有方法
  • 使用具名函数提升调试友好性
正确处理异常传递
Lambda中无法直接抛出受检异常,需进行封装转换:

@FunctionalInterface
public interface ThrowingFunction<T, R> {
    R apply(T t) throws Exception;
}

public static <T, R> Function<T, R> unchecked(ThrowingFunction<T, R> f) {
    return t -> {
        try {
            return f.apply(t);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    };
}
警惕变量捕获的副作用
Lambda捕获外部变量时,该变量必须是“有效final”。修改被捕获的局部变量会引发编译错误。
场景推荐做法
循环中创建Lambda避免使用循环索引变量,改用集合元素或流式处理
共享状态访问使用原子类或同步机制保护共享数据
优先使用方法引用提升性能
方法引用比Lambda更高效,且在JVM层面有更多优化空间。例如,String::length 比 s -> s.length() 更优。
[Stream Pipeline Execution] Source → Filter → Map (Method Ref) → Collect ↓ ↓ Predicate Function.identity()
SAP CPI 和 PO 的区别 SAP CPI适合云集成轻量级的集成需求,并且由于其云架构,具有快速部署低维护高度可扩展的特点。SAP PO更适合本地系统集成复杂的集成场景和高度定制化的需求,并且对于已经有 SAP 基础设施的企业来说,PO 提供了更多的控制和灵活性。选择使用哪个平台通常取决于企业的技术架构、集成需求、预算以及对灵活性和控制的需求。如果企业主要使用 SAP 的本地系统,并且有复杂的集成需求,那么 SAP PO 是一个理想的选择。如果企业更多地依赖云应用,并希望简化集成操作,那么 SAP CPI 更加适合。 阅读详情

相关推荐

突发E层(Es层):短波通信中的“意外惊喜”与“隐形杀手”全解析

本文深入解析了突发E层(Es层)在短波通信中的双重作用,既可能带来超远距离通信的“意外惊喜”,也可能成为通信链路的“隐形杀手”。通过分析Es层的形成机制、时空分布规律及实战应用技巧,帮助通信爱好者与专业人员更好地利用或应对这一电离层现象,提升短波通信的可靠性与效率。

weixin_30443813的博客 822

网易Unity笔试深度解析:底层原理与工程实践避坑指南

Unity3D开发工程师的笔试往往不只考察API调用,更看重对C#内存模型、引擎生命周期、资源管理等底层机制的理解。从值类型与引用类型的栈堆分配,到协程与多线程的本质区别,再到AssetBundle依赖管理与持久化路径的跨平台陷阱,每一处细节都直接影响游戏的运行性能与热更新稳定性。掌握这些原理,能帮助开发者在资源加载、性能优化及渲染管线等真实业务场景中做出更合理的技术决策,避免因“只会用不会想”而在大厂筛选中失利。本文结合网易校招真题方向,系统梳理高频考点与常见误区,为备战游戏开发岗位的读者提供一条从基础概

weixin_30166691的博客 294

NXP S32K3xx 多次复位(reset)后MCU跑死、崩溃、出错分析

s32k3出现多次复位后死机的情况

HeFlyYoung的博客 9514

c#闭包问题

而在第二个正确的例子里,在每一次循环中,会创建一个新的临时变量u来保存当前循环的i,当委托或Lambda创建时,闭包这个新的临时变量u,且每个不同委托引用的u是互相独立的,其到委托执行时都是不会变化的,所以使用临时变量来保存匿名函数想要引用的外部函数变量可以解决闭包陷阱。“foreach”的遍历中定义的临时循环变量会被逻辑上限制在循环内,“foreach”的每次循环都会是循环变量的一个拷贝,这样闭包就看起来关闭了(没有了)。在c#中,内层的函数可以引用包含在它外层的函数的变量,即使外层函数的执行已经终止。

qq_41184334的博客 1569

IDC 数据中心工程师面试题汇总

(适用于:IDC运维、机房值班、机房工程师、机柜运维、IDC基础设施、IDC网络运维岗)

老韩的Linux云计算架构师进阶之路 1070

QT开发技术 [QXlsx 导出大量数据的崩溃大坑]

QXlsx 是一个基于 Qt 框架开发的开源库,用于读写 Excel 文件(.xlsx 格式),无需依赖 Microsoft Office 或第三方库。以下从多个方面为你详细介绍 QXlsx:主要特性读写功能:支持创建、读取和修改 Excel 文件,能处理单元格的数值、公式、格式等基本操作。样式设置:可以设置单元格的字体、颜色、对齐方式、边框等样式,还能创建自定义样式并应用到多个单元格。图表支持:支持创建多种类型的图表,如柱状图、折线图、饼图等,并能对图表的样式和属性进行配置。

weixin_45397344的博客 653

C# 经常遇到的闭包问题

C# 经典闭包问题

博客 820

tsmc12: m0po max length问题(H384.M0_PO.L.1)

手动调整可以挪cell,制造上下两个row相对的至少一个site的空间,通过插普通filler来解决,这里需要注意的是,tsmc12有via0的规则,需要让via0落在via0 grid上。在pt eco之后会有一些m0po max length问题出现,大部分问题都可以通过替换decap来解决,少部分由于局部density过高,需要手动调整。更多学习内容请关注「拾陆楼」知识星球。#ICC2中替换decap的参考脚本。

m0_61544122的博客 790

C#:深入理解 lambda表达式与闭包

1. Lambda表达式 1.1 简述Lambda表达式 Lambda表达式实际上是简化委托的写法,只要有委托参数类型的地方,就可以使用Lambda表达式表示。 为了比较委托写法与Lambda表达式的差异,实现两个int类型相加的委托进行对比: 委托写法: Action<int, int> act = Add; ​ public static void Add(int a,int b) { Console.WriteLine(a + b); } Lambda表达式: A

YoungProgrammer的专栏 2678

智能车图像处理5-入门级分析4 ---环岛的状态机与补线

PS :入门级文章适合新手,如果已经有基础可以去看进阶篇文章。

taiyuezyh的博客 8230

国科大学习资料--VLSI测试与可测试设计--2020期末考试试题

国科大学习资料–VLSI测试与可测试设计–2020期末考试试题 国科大学习资料–VLSI测试与可测试设计–2020期末考试试题 国科大学习资料–VLSI测试与可测试设计–2020期末考试试题 一、概念题 1简述可测试性测度与两个主要的测度指标的含义; 2以March C-算法为例,说明March算法的构成,以及March C-算法的故障覆盖率; 3“效果-原因”诊断法和“原因效果诊断法”的不同; 4列举四条扫描设计时出现的问 题及解决办法; 5最少写出1149.1与1500的五点不同; = = = = =

无名何许人的博客 1150

【C#】闭包

关于C#闭包的分析

m0_62389241的博客 2100

从源码编译CesiumForUnreal

从源码编译CesiumForUnreal插件

专注GIS开发 5643

C# lambda 表达式 和 闭包的概念

第二次执行事件中的两个匿名函数时,第一个匿名函数执行时value的值变为了20 所以输出20 第二个匿名函数value地址中存的值变为了30所以输出30。Console.WriteLine("有返回值有参数的那么大表达式{0}", value);Console.WriteLine("省略参数类型的写法{0}", value);这两次输出不同证明了事件中存的匿名函数中的vlue是存的成员变量value的地址。//因为 当构造函数执行完毕时 其中申明的临时变量value的生命周期被改变了。

m0_53393728的博客 1237

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

Unity性能分析五大误区:从Profiler数据到精准优化实战

性能分析是游戏开发中保障流畅体验的核心环节,其本质是通过数据监控理解应用运行状态。其原理在于采集CPU、内存、渲染等模块的运行时指标,构建性能画像。这项技术的价值在于能系统性定位瓶颈,避免盲目优化,提升开发效率。在Unity游戏开发中,性能分析广泛应用于实时帧率监控、内存泄漏排查、加载耗时优化等场景。然而,实践中常因认知偏差导致分析失效,例如过度关注平均帧时间而忽视导致卡顿的帧时间分布峰值,或仅监控总内存而忽略由高频托管堆分配引发的GC(垃圾回收)卡顿。掌握正确的分析思维与工具链,是发挥性能分析效能、实现精

weixin_30522183的博客 546

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

Python设计模式退化:从GOF到协议思维的工程演进

设计模式本质是语言表达力不足时的结构补偿机制。在Java、C#等静态类型语言中,Strategy、Observer、Factory等模式通过类继承与接口约束显式建模行为契约;而Python凭借函数即对象、鸭子类型、装饰器和Protocol协议等原生特性,将大量模式逻辑下沉为运行时语义或数据结构,实现‘隐式契约’替代‘显式接口’。这种范式迁移提升了代码可读性、可测试性与迭代效率,尤其适用于微服务快速验证、跨语言重构及动态系统集成场景。本文聚焦Python中设计模式的自然退化现象,结合真实生产案例解析协议驱动、

didi9310的博客 372

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

C#闭包详解

在这种情况下,委托里引用的变量都是同一个i,所以编译器只会生成一个匿名类DisplayClass,并且把它赋值给数组的十个位置。如果用下面这种代码,每次循环都声明一个新的变量temp,那就会导致生成十个DisplayClass的实例。

超胆孤侠 2411

学习笔记——C#的闭包

Lambda表达式实际上是简化委托的写法,只要有委托参数类型的地方,就可以使用Lambda表达式表示。

m0_63869023的博客 646

C# 闭包的理解

C#闭包,JavaScript闭包。

qq_38192821的博客 566

C#——委托、Lambda表达式、闭包和内存泄漏

使用委托的典型情况使用Lambda表达式初始化委托闭包关于foreach语句的闭包闭包?内存泄漏?总结1、匿名函数是个语法糖,很方便,但是也容易带来问题。2、如果一定要使用闭包,那么切记做好内存的回收。3、养成良好的代码习惯。

波波诸葛伟 513

C#中闭包的实现和注意事项

闭包并不是某一个语言中特有的概念,在主流的编程语言中都有这个特性。闭包可以让一个内部方法可以访问它所在外部方法中的变量,并可以对变量的值进行修改,即使在外部方法的生命周期已经结束后。不知道在看完上面这一串定义之后,可以明白闭包是个什么东西吗,反正我在一开始看完是不知道这是在说什么,不过没关系,我们可以先往下具体看闭包的一个例子。

m0_59293490的博客 984

编码技巧 --- 谨防闭包陷阱

引言先不论什么是闭包,什么是闭包陷阱,我们开篇先看一段代码:static void Main(string[] args) { List<Action> lists = new List<Action>(); for (int i = 0; i < 5; i++) { Action action = () => { Co...

dotNET跨平台 201

闭包(C#)

通常来讲,大家一听到闭包,应该首先会想到JavaScript中的闭包,而不会想到C#中的闭包,但是C#中也是有闭包的,下面就让我来为大家仔细讲解讲解。 在C#中,我们通常知道变量作用域有三种:1、是属于类的,我们常称之为field,2、是属于函数的,我们通常称之为局部变量,3、其实也是属于函数的,不过它的作用范围更小,它只属于函数局部的代码片段,这种我们同样称之为局部变量。

草原上唱山歌的博客 1595

C#学习笔记(三十三) lambda 闭包

闭包 通过Lambda表达式访问Lambda表达式块外部的变量,称为闭包。 private static void Main() { // 闭包 int val = 10; Func<int,int> action = (params1) => ...

EngraveSmile的专栏 685

C# Lambda 和 匿名函数的GC总结

C#闭包与GC相关

vinkey_st的博客 1381

C#lambda与闭包的个人理解

1.lambada: 任何 Lambda 表达式都可以转换为委托类型。 Lambda 表达式可以转换的委托类型由其参数和返回值的类型定义。 如果 lambda 表达式不返回值,则可以将其转换为 Action 委托类型之一;否则,可将其转换为 Func 委托类型之一。注意的是,委托并不关心类,只关心关联方法的参数和返回值类型是否一致。 2.属性与lambada: 当一个属性 string demoString=>“One String”; 就会把return "One String"作为demoStri

weixin_47028101的博客 668
上一篇: 【C#开发者必看】5种提升数据排序效率的关键技巧,第3个少有人知
下一篇: 揭秘PHP微服务服务注册难题:3步实现自动化注册与发现
CompiGlow
博客等级 码龄1年 159粉丝 1987原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值