深入C# 12主构造函数机制:解锁record类型高效编程的3个关键点

第一章:C# 12主构造函数与record类型的核心演进

C# 12 引入了主构造函数(Primary Constructors)这一重要语言特性,显著简化了类和 record 类型的定义方式,尤其在处理不可变数据模型时提升了代码的可读性与简洁性。

主构造函数的基本语法

在 C# 12 中,可以在类或 record 的声明级别直接定义构造参数,这些参数可用于初始化内部字段或属性。主构造函数的参数作用域覆盖整个类型体,允许在属性、方法中直接使用。
// 使用主构造函数定义一个 record
public record Person(string Name, int Age)
{
    // 可在方法中直接使用构造参数
    public bool IsAdult => Age >= 18;

    public void Introduce()
    {
        Console.WriteLine($"Hello, I'm {Name}, {Age} years old.");
    }
}
上述代码中,Person record 的构造参数 Name 和 Age 自动成为公共只读属性,且编译器生成相应的构造函数逻辑。

主构造函数与传统构造函数的对比

通过表格可以清晰看出语法上的演进:
特性C# 11 及之前C# 12 主构造函数
构造方式需显式声明构造函数和私有字段在类型声明处定义参数
代码冗余较高,需重复赋值极低,自动提升为属性
适用场景通用类设计数据承载类型,尤其是 record

结合 init 赋值与主构造函数

尽管主构造函数提供了简洁的初始化方式,但若需额外验证或转换逻辑,仍可在类型内部定义成员构造函数,并结合 init 访问器确保不可变性:
public record Product(decimal Price)
{
    public decimal Price { get; init; } = Price > 0 ? Price : throw new ArgumentException("Price must be positive.");
}
该示例展示了如何在属性中加入校验逻辑,增强数据完整性。主构造函数与 record 的融合标志着 C# 在面向表达式编程和不可变数据建模上的持续进化。

第二章:主构造函数在记录类型中的扩展能力

2.1 理解主构造函数的语法简化与语义增强

在现代编程语言设计中,主构造函数的语法简化显著提升了类定义的简洁性与可读性。通过将构造参数直接集成到类声明中,开发者无需重复编写字段赋值逻辑。
语法结构示例
class Person(val name: String, var age: Int) {
    init {
        require(age >= 0) { "Age cannot be negative" }
    }
}
上述 Kotlin 代码中,name 和 age 在主构造函数中声明并自动创建为类属性,省略了传统冗余的字段初始化过程。参数前的 val 和 var 关键字分别表示只读和可变属性。
语义优势分析
  • 减少样板代码,提升开发效率
  • 增强类声明的内聚性与表达力
  • 支持默认参数与可见性修饰符的直接应用
这种设计不仅降低了出错概率,还使构造逻辑更易于维护与理解。

2.2 主构造函数如何提升record类型的封装性

在C#中,record类型通过主构造函数实现了更紧凑和安全的封装机制。主构造函数允许在定义record时直接声明参数,并自动将其绑定到属性上,避免手动实现构造逻辑。
主构造函数语法示例
public record Person(string Name, int Age);
上述代码中,Name和Age由主构造函数声明,编译器自动生成对应的只读属性与构造函数,确保状态初始化的一致性。
封装性增强机制
  • 参数自动提升为私有字段或属性,外部无法绕过构造逻辑直接赋值;
  • 支持在主构造函数中添加验证逻辑,如使用: this调用私有构造函数进行参数校验;
  • 结合init访问器,可在构造期间设置属性,之后禁止修改,强化不可变性。
这种设计减少了模板代码,同时提升了数据类型的封装强度与一致性保障。

2.3 基于主构造函数的自动属性初始化机制解析

在现代C#语言中,主构造函数(Primary Constructor)允许在类定义时直接声明参数,并用于自动初始化属性。这一机制简化了对象初始化流程,提升了代码可读性。
语法结构与示例
public class Person(string name, int age)
{
    public string Name { get; } = name;
    public int Age { get; } = age;
}
上述代码中,Person类的主构造函数接收name和age参数,自动用于初始化只读属性。编译器会生成私有字段并完成赋值,无需显式编写构造函数体。
执行流程分析
初始化顺序如下:
  1. 调用主构造函数传入参数
  2. 按声明顺序执行属性初始化器
  3. 完成实例构建
该机制有效减少了模板代码,同时保障封装性与不可变性。

2.4 实践:使用主构造函数构建不可变数据模型

在现代编程语言中,主构造函数为定义不可变数据模型提供了简洁且类型安全的方式。通过在构造函数中直接声明属性,对象初始化与字段赋值一步完成。
不可变性的优势
不可变对象天然具备线程安全性,避免了状态变更带来的副作用。主构造函数结合 val 关键字可确保字段仅初始化一次。
data class User(val id: Long, val name: String, val email: String)
上述 Kotlin 代码中,User 类的三个属性均为只读。主构造函数参数前的 val 使其成为类的不可变属性,编译器自动生成 equals、hashCode 和 toString 方法。
实践建议
  • 优先使用 val 而非 var 声明构造参数
  • 结合 data class 提升数据模型表达力
  • 利用默认参数值增强构造灵活性

2.5 扩展场景:主构造函数与泛型record的协同应用

在现代C#开发中,主构造函数与泛型record的结合为不可变数据结构的设计提供了强大支持。通过主构造函数,可以在类型定义时直接声明参数,并自动初始化只读属性。
基本语法结构
public record PersonRecord(string Name, int Age);
该语法利用主构造函数自动生成只读属性和相等性比较逻辑,简化了传统类的冗长定义。
泛型扩展能力
引入泛型后,可构建通用的数据载体:
public record Result<T>(bool Success, T? Data, string? Error);
此模式广泛应用于API响应封装,其中T代表任意业务数据类型,Success标识执行状态。
  • 主构造函数减少样板代码
  • 泛型增强类型安全性
  • record语义保障值相等性与不可变性

第三章:记录类型中主构造函数的关键限制

3.1 主构造函数无法支持多构造函数重载的深层原因

在面向对象语言中,主构造函数的设计初衷是简化对象初始化流程。然而,其本质限制导致难以直接支持多构造函数重载。
语言设计层面的约束
多数现代语言(如 Kotlin、Scala)将主构造函数绑定到类声明头部,使其仅能存在一个形式参数列表。这种语法结构排除了在同一位置重复定义多个参数签名的可能性。
重载机制的底层冲突
  • 构造函数重载依赖参数数量或类型差异来区分调用路径
  • 主构造函数不允许多个独立签名共存
  • 编译器无法为同一主构造函数生成多个入口点
class User(val name: String, val age: Int) {
    // 辅助构造函数需委托主构造函数
    constructor(name: String) : this(name, 0)
}
上述代码中,次构造函数必须通过 this() 显式委托主构造函数,表明主构造函数处于初始化链顶端,无法被并列重载。

3.2 可变状态管理的边界与设计约束

在复杂系统中,可变状态的管理必须明确边界,以避免副作用扩散。合理的状态更新应通过预定义的入口进行,确保数据流可控。
状态变更的受控路径
使用不可变更新模式可以有效降低状态误变风险。例如,在 Go 中通过结构体复制实现安全更新:

type AppState struct {
    Users map[string]string
}

func (a *AppState) UpdateUser(id, name string) AppState {
    updated := *a
    updated.Users = make(map[string]string)
    for k, v := range a.Users {
        updated.Users[k] = v
    }
    updated.Users[id] = name
    return updated
}
该方法返回新实例而非修改原状态,避免共享可变状态带来的竞态问题。
设计约束清单
  • 禁止跨模块直接修改状态
  • 所有变更需通过声明式动作触发
  • 状态快照应支持回滚能力

3.3 序列化与反射场景下的兼容性挑战

在跨平台或跨版本系统交互中,序列化数据的结构变化常引发反射解析失败。当目标类型字段增减或类型变更时,反序列化过程可能抛出运行时异常。
典型问题场景
  • 字段名称不一致导致反射赋值失败
  • 枚举值扩展后旧客户端无法识别
  • 嵌套结构体层级变更破坏映射路径
代码示例:Go 中的 JSON 反序列化兼容处理

type User struct {
    ID   int    `json:"id"`
    Name string `json:"name,omitempty"`
    Age  *int   `json:"age"` // 使用指针支持缺失字段
}
上述代码通过指针类型和 omitempty 标签增强兼容性。Age 字段若在 JSON 中缺失,将保留 nil 而非默认 0,避免误判用户年龄为 0。
兼容性设计建议
策略说明
字段可选化使用指针或包装类型表示可选字段
版本标记在序列化数据中嵌入 schema 版本号

第四章:规避限制的最佳实践与替代方案

4.1 利用init访问器补充构造时的灵活赋值需求

在现代编程语言中,对象初始化过程常面临字段赋值灵活性不足的问题。`init` 访问器提供了一种在构造阶段安全设置属性的机制,兼具封装性与初始化自由度。
init访问器的核心优势
  • 允许属性在对象构造期间被赋值,之后变为只读
  • 增强封装性,避免暴露 public setter
  • 支持记录(record)和不可变类型的构建
代码示例:C# 中的 init 访问器

public class User
{
    public string Name { get; init; }
    public int Age { get; set; }
}
// 构造时赋值
var user = new User { Name = "Alice", Age = 30 };
// user.Name = "Bob"; // 编译错误:Name 只能在初始化时设置
上述代码中,Name 属性使用 init 而非 set,确保其仅在对象初始化阶段可被赋值,提升数据安全性。该机制特别适用于配置对象、DTO 和不可变模型的设计场景。

4.2 静态工厂方法模式绕过多构造函数限制

在Java等语言中,重载构造函数虽能提供多种实例化方式,但参数过多时易导致可读性差和组合爆炸问题。静态工厂方法通过命名清晰的静态方法创建对象,有效规避这一限制。
优势与实现方式
  • 方法名可表达意图,如 valueOf 表示类型转换
  • 避免重复的参数列表,提升代码可维护性
  • 可返回子类或缓存实例,支持更灵活的对象管理
public class BooleanWrapper {
    private final boolean value;

    private BooleanWrapper(boolean value) {
        this.value = value;
    }

    public static BooleanWrapper trueInstance() {
        return new BooleanWrapper(true);
    }

    public static BooleanWrapper falseInstance() {
        return new BooleanWrapper(false);
    }

    public static BooleanWrapper fromValue(boolean value) {
        return value ? trueInstance() : falseInstance();
    }
}
上述代码中,trueInstance() 和 falseInstance() 提供语义化实例创建入口,fromValue() 根据参数返回对应实例,逻辑清晰且易于扩展。

4.3 使用partial record实现跨文件逻辑扩展

在复杂系统开发中,单个记录类型可能需要分布在多个文件中进行维护。F# 的 partial record 机制允许将一个 record 的定义拆分到不同文件,通过扩展成员实现逻辑解耦。
语法结构与使用方式

[<AbstractClass; Sealed>]
type UserExtensions = 
    static member WithEmail (user: User) email = { user with Email = email }
上述代码通过静态成员扩展 record 行为,实现跨文件添加功能。User 定义可在另一文件中声明,而扩展方法独立维护。
  • 支持职责分离,提升模块可维护性
  • 避免单文件过大,便于团队协作
  • 结合模块嵌套可实现命名空间级别的组织

4.4 通过继承与with表达式优化不可变类型操作

在处理不可变数据结构时,频繁的复制操作可能导致性能损耗。通过继承机制,可复用基类的不可变逻辑,减少重复代码。
使用 with 表达式简化副本创建
C# 中的 with 表达式结合记录类型(record),能高效生成修改后的副本:

public record Person(string Name, int Age);
var p1 = new Person("Alice", 30);
var p2 = p1 with { Age = 31 };
上述代码中,p1 创建后无法修改。通过 with 表达式,仅声明需变更的属性,即可创建新实例 p2,其余字段自动继承。该语法底层利用复制构造函数,确保不可变性的同时提升语义清晰度。
继承增强可扩展性
  • 子类可扩展记录字段而不破坏原有不可变契约
  • with 操作保持多态行为,支持深度副本生成

第五章:总结:主构造函数对现代C#开发的影响与展望

提升代码简洁性与可维护性
主构造函数的引入显著减少了样板代码。以往需要手动声明字段并编写构造函数初始化逻辑,现在可通过一行语法完成。

public class Person(string name, int age)
{
    public string Name { get; } = name;
    public int Age { get; } = age;
}
该语法不仅缩短了类定义长度,还隐式保证了不可变性,适用于 DTO 和领域模型。
推动函数式编程风格
主构造函数常与记录类型(record)结合使用,强化了值语义和不可变数据结构的理念。在高并发或纯函数场景中尤为重要。
  • 减少因状态变更引发的竞态条件
  • 提升单元测试的确定性
  • 简化对象比较逻辑(默认实现 Equals、GetHashCode)
例如,在 ASP.NET Core 中定义 API 响应模型时,主构造函数能快速构建不可变输出:

public record ApiResponse(bool Success, T? Data, string[] Errors);
与依赖注入框架的协同演进
虽然主构造函数不直接用于服务注册,但在配置选项类中极具价值。例如使用 IOptions<T> 模式时:
场景传统方式主构造函数方式
配置类定义需显式属性 + 构造函数一行声明完成
代码行数6-8 行1-2 行
[Configuration] → [Options Class with Primary CTOR] → [IOptionsSnapshot]
突破限制:在.NetFramework项目中解锁C# 10.0新特性的实战指南 本文提供了一份实战指南,帮助开发者在无需升级.NET Framework运行时的情况下,解锁并使用C# 10.0的新特性。通过强制指定语言版本(LangVersion)和添加必要的编译器支持类型(如IsExternalInit),可以在传统项目中安全地应用record类型、init属性、全局using指令等现代语法,显著提升代码简洁性与开发效率,尤其适合受框架限制的遗留系统升级。 阅读详情

相关推荐

基于UDS的BootLoader上位机源代码,支持ISO15765通信,支持PeakCAN , ZJG CAN等CAN卡, 支持S-record格式的二进制文件解析; 可二次开发或扩展应用

基于UDS的BootLoader上位机源代码(C#) 基于UDS的BootLoader上位机源代码,支持ISO15765通信,支持PeakCAN , ZJG CAN等CAN卡, 支持S-record格式的二进制文件解析; 可二次开发或扩展应用。YID:925000632927820924时间煮雨_______ 基于UDS烧录的上位机源代码使用说明 1.总体说明 1.1.设备(CAN卡)操作 (1)软件集成了PCAN USB的设备操作,硬件设备的操作参考了设备的官方例程,本软件中仅使用了设备启动和关闭,

m0_72518029的博客 1441

解锁C#高效编程:10个进阶技巧助力代码质效双升

在C#开发中,类的成员(如属性、方法、构造函数等)定义往往需要编写大量的样板代码,尤其是在一些简单的成员实现中,这些样板代码会显得冗余且影响代码的可读性。C#6.0引入的表达式体成员语法,允许使用箭头表达式=>来简化类成员的定义,让代码更简洁、紧凑。要实现自定义对象的解构赋值,需要在类中定义一个无返回值、名称为的方法,并通过out参数指定需要解构的成员。set;set;set;// 定义解构方法// 自定义对象的解构赋值。

weixin_54447959的博客 862

C# 10 vs .NET 6:探索10项创新特性,解锁编程新境界

C# 10与.NET 6的携手,为开发者带来了不仅是语法糖的甜蜜,更是效率与生产力的飞跃。这些新特性,每一项都像是精心雕琢的工具,为你的编程之旅增添无限可能。掌握它们,就像拥有了一把钥匙,打开了通往高效、优雅编程世界的大门。让我们一起,踏上这场创新的征途,探索C# 10的无限魅力!

java专栏 483

基于UDS的BootLoader上位机源代码(C#):支持多种CAN卡与S-record格式解...

本文档详细解读基于UDS(Unified Diagnostic Services,统一诊断服务)的BootLoader上位机源代码,该软件采用C#语言,依托Visual Studio 2013开发环境构建,核心功能是通过CAN总线实现对MCU(微控制单元)的固件升级。

NBhhbYyOljP的博客 1597

下载Python3.10的相关方法及问题解决

下载Python3.10的相关方法及问题解决 报错unable to locate package python3.10-dev以及subprocess.CalledProcessError: Command ‘(‘lsb_release‘, ‘-a‘)‘ returned non-zero exit status 1问题解决

Istil 1555

CAD图纸智能搜索三大突破:图纸秒搜技术、相似度匹配与AI语义搜索

CAD图纸作为核心资产,长期面临管理难题:传统全文检索需逐张打开图纸人工查找,效率低下;相似图纸匹配依赖人工比对,误差率高;非专业人员难以通过模糊描述精准定位图纸。针对这些问题,唯杰地图推出三项智能解决方案:一是基于现代化索引引擎的​​全文搜索​​,支持秒级检索图纸内的文字、图层、块名称等,并可多条件组合查询;二是​​相似度搜索​​,通过SIFT算法和深度学习提取几何特征与拓扑结构,实现高精度匹配;三是​​AI语义搜索​​,利用大模型解析自然语言指令(如“查找半径为10的红色圆”),直接定位目标图形。

vjmap的博客 1869

工控开发者的福音:在.NetFramework项目中解锁C# 10.0新特性的3个关键步骤

本文为工控开发者提供了在 .NET Framework 项目中安全解锁 C# 10.0 新特性的完整实战指南。通过三个关键步骤:切换编译器语言版本、添加运行时补丁文件以及优化开发体验,开发者可以在不升级框架、不破坏现有系统兼容性的前提下,使用 record、全局 using 等现代语法特性,显著提升代码可维护性和开发效率。

h6j7k8l9p0的博客 683

华为Atlas 300I推理卡驱动安装避坑指南:不同安装方式的选择与优化

本文详细解析华为Atlas 300I推理卡驱动安装的三种主流方式(.run、.rpm和源码编译),提供关键环境检查步骤、安装流程优化建议及常见问题解决方案,帮助开发者高效完成芯片推理卡部署并规避典型安装陷阱。

q9w8e7r6t5的博客 432

基于UDS的BootLoader上位机源代码(C#),支持多种CAN卡与S-record格式解析

源代码通过枚举明确设备操作范围,通过静态类统一管理设备参数,避免参数混乱。设备操作类型枚举(DeviceOperationType):定义(无操作)、(打开设备)、(关闭设备)三类操作,限定设备操作的合法范围,避免非法操作触发硬件异常。设备类型枚举(DeviceType):区分(PeakCAN设备)、(周立功设备),为后续差异化操作提供判断依据。静态参数类静态类存储PeakCAN设备核心参数(设备句柄、mBaudrte波特率、m HwType硬件类型);静态类存储周立功设备参数(zlgdevType。

2501_93693767的博客 1374

基于STM32、HAL库的GZP6816D气压传感器 驱动程序设计

测量范围:0-16kPa(可根据型号不同有变化)工作电压:1.8V-3.6V。高精度:±1% FS。

corlin6688的博客 219

SAP 中租赁资产的实现需区分经营租赁与融资租赁,核心围绕资产主数据配置、折旧与利息设置、科目分配及业务操作展开

摘要:SAP系统租赁资产管理需区分经营租赁与融资租赁,通过SPRO配置资产主数据、折旧范围、利息计算及科目分配。关键步骤包括:激活折旧范围利息计算(OABZ)、设置租赁资产类别(OAYZ)、维护总账科目(AO90)及创建租赁资产主数据(AS01)。业务操作涵盖资产资本化(ABZON)、折旧利息过账(AFAB)、租金支付(F-53)及终止处理(ABUMN)。核心配置要点在于准确设置租赁类型、利率参数和科目联动,确保系统自动计算折旧与利息并生成正确凭证。

金牌架构师 1073

从C# 1.0到9.0:Unity开发者必须知道的版本特性与实战避坑指南

本文详细解析了从C# 1.0到9.0各版本特性在Unity开发中的实际应用与避坑指南,特别针对Unity版本与C#版本的适配关系、异步编程、模式匹配等核心特性进行深入探讨。帮助开发者高效利用新语法提升游戏开发效率,同时规避版本错配带来的风险。

weixin_30882895的博客 252

指纹对抗指南:如何绕过Cloudflare与Akamai的5s盾与浏览器指纹检测

现在的CDN反爬技术虽然越来越强,但是道高一尺魔高一丈,只要掌握了指纹伪造、流量伪装、行为模拟这些核心技术,就可以绕过绝大多数的防护措施。对抗过程中要注意效率和成本的平衡,小规模爬取用Playwright+stealth最方便,大规模爬取用curl_cffi+代理池性价比最高,遇到验证码用打码平台或者自动识别服务,不需要死磕破解。本文介绍的方案已经在实战中验证过,可以绕过95%以上的Cloudflare/Akamai防护,成功率非常高。

专注于Python爬虫开发,分享爬虫技巧、项目实战与反爬经验,使用Scrapy、BeautifulSoup等工具,解决数据抓取难题。 297

基于UDS的BootLoader上位机源代码(C#) 基于UDS的BootLoader上位机源代码

源代码通过枚举明确设备操作范围,通过静态类统一管理设备参数,避免参数混乱。设备操作类型枚举(DeviceOperationType):定义(无操作)、(打开设备)、(关闭设备)三类操作,限定设备操作的合法范围,避免非法操作触发硬件异常。设备类型枚举(DeviceType):区分(PeakCAN设备)、(周立功设备),为后续差异化操作提供判断依据。静态参数类静态类存储PeakCAN设备核心参数(设备句柄、mBaudrte波特率、m HwType硬件类型);静态类存储周立功设备参数(zlgdevType。

weixin_46579091的博客 1744

Unity 横版游戏开发天花板?状态机、联机同步与横版动作游戏架构全都有

在 Unity 横版动作游戏开发领域,最耗时间的往往不是角色移动,而是整套“可扩展架构”的搭建。包括角色状态管理、敌人 AI、武器系统、关卡编辑器、联机同步、输入适配、UI 与存档系统等。2D Action Platformer Kit 的核心价值,并不只是“提供素材”,而是它已经帮开发者搭好了一整套适用于横版动作游戏的底层框架。

2403_88403568的博客 425

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

Dunet:C革命性判别联合生成器,让代码更简洁高效的终极指南

Dunet是一个革命性的C#源代码生成器,专门用于创建判别联合(Discriminated Union)类型。这个强大的工具让C#开发者能够以更简洁、更安全、更高效的方式处理复杂的业务逻辑和数据结构。在前100个字内,Dunet的核心关键词"判别联合生成器"已经出现,这正是它最核心的功能:自动生成类型安全的联合类型代码,彻底改变你在C#中处理多态数据的方式。🚀 ## 为什么你需要Dunet判别

gitblog_00734的博客 363

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

基于UDS的BootLoader上位机源代码(C#):支持ISO通信与多种CAN卡,S-rec...

源代码通过枚举明确设备操作范围,通过静态类统一管理设备参数,避免参数混乱。设备操作类型枚举(DeviceOperationType):定义(无操作)、(打开设备)、(关闭设备)三类操作,限定设备操作的合法范围,避免非法操作触发硬件异常。设备类型枚举(DeviceType):区分(PeakCAN设备)、(周立功设备),为后续差异化操作提供判断依据。静态参数类静态类存储PeakCAN设备核心参数(设备句柄、mBaudrte波特率、m HwType硬件类型);静态类存储周立功设备参数(zlgdevType。

2508_94229148的博客 673

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain&#39;s apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath(&#39;DeepLearnToolbox&#39;));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand(&#39;state&#39;,0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W&#39;); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand(&#39;state&#39;,0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = &#39;sigm&#39;;%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, &#39;Too big error&#39;);```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand(&#39;state&#39;,0)sae = saesetup([784 100]);sae.ae{1}.activation_function = &#39;sigm&#39;;sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)&#39;)% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = &#39;sigm&#39;;nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, &#39;Too big error&#39;);```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x&#39;,28,28,60000))/255;test_x = double(reshape(test_x&#39;,28,28,10000))/255;train_y = double(train_y&#39;);test_y = double(test_y&#39;);%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you&#39;ll get around 1.2% errorrand(&#39;state&#39;,0)cnn.layers = { struct(&#39;type&#39;, &#39;i&#39;) %input layer struct(&#39;type&#39;, &#39;c&#39;, &#39;outputmaps&#39;, 6, &#39;kernelsize&#39;, 5) %convolution layer struct(&#39;type&#39;, &#39;s&#39;, &#39;scale&#39;, 2) %sub sampling layer struct(&#39;type&#39;, &#39;c&#39;, &#39;outputmaps&#39;, 12, &#39;kernelsize&#39;, 5) %convolution layer struct(&#39;type&#39;, &#39;s&#39;, &#39;scale&#39;, 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, &#39;Too big error&#39;);```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand(&#39;state&#39;,0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, &#39;Too big error&#39;);%% ex2 neural net with L2 weight decayrand(&#39;state&#39;,0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, &#39;Too big error&#39;);%% ex3 neural net with dropoutrand(&#39;state&#39;,0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, &#39;Too big error&#39;);%% ex4 neural net with sigmoid activation functionrand(&#39;state&#39;,0)nn = nnsetup([784 100 10]);nn.activation_function = &#39;sigm&#39;; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, &#39;Too big error&#39;);%% ex5 plotting functionalityrand(&#39;state&#39;,0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = &#39;softmax&#39;; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, &#39;Too big error&#39;);%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand(&#39;state&#39;,0)nn = nnsetup([784 20 10]); nn.output = &#39;softmax&#39;; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, &#39;Too big error&#39;);```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

进阶C#开发:10个被低估但能提升代码质量的关键字

进阶C#开发:10个被低估但能提升代码质量的关键字

寒冰屋的专栏 14
上一篇: 从零构建DOTS项目,手把手教你用C#打造高效ECS框架
下一篇: 容器编译耗时降低80%?揭秘Symfony 7 DI优化背后的秘密
QuickSolve
博客等级 码龄1年 137粉丝 2015原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值