VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > 编程开发 > c#编程 >
  • 匿名类型与动态对象——C#测试临时数据封装实例

第一部分:C#基础入门
实例8:匿名类型与动态对象——临时数据封装
实例介绍
在日常开发中,我们经常需要临时存储一些不需要持久化的数据:比如数据库查询的中间结果、前端传递的临时参数、接口返回的非结构化数据。此时,创建专门的实体类会显得冗余,而匿名类型和动态对象就是最佳解决方案:
匿名类型:适合强类型的临时数据(结构固定、属性明确),比如封装用户的“姓名+年龄+邮箱”临时信息;
动态对象:适合不确定类型的临时数据(结构可变、属性未知),比如处理前端传来的JSON、COM组件交互、动态脚本调用。
本实例通过两个场景带你掌握匿名类型和动态对象的核心用法:用匿名类vb.net教程C#教程python教程SQL教程access 2010教程型封装查询结果,用动态对象处理JSON数据,对比两者的区别与适用场景,学会在合适的场景选择合适的工具。
需求分析
1.匿名类型场景:从数据库查询用户信息时,仅需临时返回“姓名、年龄、注册时间”三个字段,无需创建实体类;
2.动态对象场景:处理前端传来的JSON数据(结构不确定,可能包含“手机号、地址”等可选字段),无需提前定义类;
3.核心验证:
匿名类型的只读特性(属性无法修改);
动态对象的运行时属性绑定(可动态添加/删除属性);
两者的类型安全性对比(编译时vs运行时检查);
4.测试验证:创建匿名对象、访问属性,动态对象的属性操作,错误处理(如动态对象访问不存在的属性)。
代码实现
csharp

	using System;
	using System.Dynamic; // 动态对象依赖的命名空间
	using Newtonsoft.Json; // 需安装Newtonsoft.Json包(处理JSON动态转换)
	
	namespace AnonymousAndDynamicDemo
	{
	class Program
	{
	static void Main(string[] args)
	{
	// ==================== 场景1:匿名类型封装临时查询结果 ====================
	Console.WriteLine("=== 匿名类型示例 ===");
	// 创建匿名对象:用var推断类型,属性自动为只读
	var tempUser = new 
	{
	Name = "张三",
	Age = 32,
	RegisterTime = DateTime.Now.AddYears(-5) // 5年前注册
	};
	// 访问匿名对象属性(编译时检查,安全)
	Console.WriteLine($"姓名:{tempUser.Name}");
	Console.WriteLine($"年龄:{tempUser.Age}");
	Console.WriteLine($"注册时间:{tempUser.RegisterTime:yyyy-MM-dd}");
	// tempUser.Name = "李四"; // ❌ 编译错误:匿名类型属性是只读的
	
	// 匿名类型的相等性:基于属性值的相等(编译器重写了Equals和GetHashCode)
	var tempUser2 = new { Name = "张三", Age = 32, RegisterTime = tempUser.RegisterTime };
	Console.WriteLine($"匿名对象相等?{tempUser.Equals(tempUser2)}"); // ✅ True
	
	
	// ==================== 场景2:动态对象处理不确定JSON数据 ====================
	Console.WriteLine("
=== 动态对象示例 ===");
	// 1. 用ExpandoObject创建动态对象(支持动态添加属性)
	dynamic dynamicUser = new ExpandoObject();
	dynamicUser.Name = "李四";
	dynamicUser.Age = 28;
	dynamicUser.Phone = "13812345678"; // 动态添加可选属性
	Console.WriteLine($"动态对象姓名:{dynamicUser.Name}");
	Console.WriteLine($"动态对象手机号:{dynamicUser.Phone}");
	
	// 2. 动态对象处理JSON数据(前端传来的非结构化数据)
	string jsonData = @"
	{
	""Name"": ""王五"",
	""Age"": 25,
	""Address"": ""北京市朝阳区"",
	""Tags"": [""技术"", ""产品""]
	}";
	dynamic jsonUser = JsonConvert.DeserializeObject<dynamic>(jsonData);
	Console.WriteLine($"JSON用户姓名:{jsonUser.Name}");
	Console.WriteLine($"JSON用户地址:{jsonUser.Address}");
	Console.WriteLine($"JSON用户标签:{jsonUser.Tags[0]}"); // 访问数组元素
	
	// 3. 动态对象的错误处理(访问不存在的属性会抛出运行时异常)
	try
	{
	Console.WriteLine(jsonUser.NonExistProperty); // ❌ 运行时错误
	}
	catch (Microsoft.CSharp.RuntimeBinder.RuntimeBinderException ex)
	{
	Console.WriteLine($"动态对象错误:{ex.Message}");
	}
	}
	}
	}

逐行讲解
场景1:匿名类型核心代码

匿名对象创建:

csharp

var tempUser = new { Name = "张三", Age = 32, RegisterTime = DateTime.Now.AddYears(-5) };

ovar关键字:匿名类型没有类名,必须用var让编译器自动推断类型;
o编译器行为:自动生成密封类(类名如<>f__AnonymousType03),属性为public readonly(只读),重写Equals/GetHashCode(基于属性值相等)。

匿名类型只读特性:
csharp

// tempUser.Name = "李四"; // ❌ 编译错误

匿名类型的属性是只读的,无法修改,确保临时数据的不可变性。

匿名类型相等性:

csharp

	var tempUser2 = new { Name = "张三", Age = 32, RegisterTime = tempUser.RegisterTime };
	Console.WriteLine(tempUser.Equals(tempUser2)); // ✅ True

编译器重写了Equals方法,只要所有属性值相等,两个匿名对象就相等(即使是不同实例)。
场景2:动态对象核心代码

ExpandoObject创建动态对象:

csharp

	dynamic dynamicUser = new ExpandoObject();
	dynamicUser.Name = "李四";
	dynamicUser.Phone = "13812345678";

ExpandoObject:实现IDictionary<string, object>,可以像字典一样添加属性(dynamicUser["Phone"] = "138..."),也可以像对象一样访问(dynamicUser.Phone);

dynamic关键字:告诉编译器不做静态类型检查,所有属性/方法绑定延迟到运行时。

动态对象处理JSON:

csharp

	dynamic jsonUser = JsonConvert.DeserializeObject<dynamic>(jsonData);
	Console.WriteLine(jsonUser.Address);

Newtonsoft.Json将JSON反序列化为JObject(实现动态绑定),可以直接访问JSON的属性,无需提前定义类;
适合处理结构不确定的JSON(比如前端传递的可选字段)。

动态对象错误处理:

csharp


	try { Console.WriteLine(jsonUser.NonExistProperty); }
	catch (RuntimeBinderException ex) { ... }

动态对象访问不存在的属性时,会抛出RuntimeBinderException(运行时错误),必须用try-catch捕获。
基础知识拓展

  1. 匿名类型vs动态对象核心区别
特性 匿名类型 动态对象
类型安全性 编译时检查(安全) 运行时检查(不安全,易出错)
属性可变性 只读(不可修改) 可读写(动态添加/删除)
性能 高(静态绑定,和普通类一致) 低(运行时绑定,比静态类型慢2-10倍)
适用场景 结构固定的临时数据(如查询中间结果) 结构不确定的数据(如JSON、COM交互)
序列化支持 Newtonsoft.Json支持,System.Text.Json默认不支持 支持(JSON反序列化直接转为动态对象)
  1. 匿名类型底层实现
    编译器会为每个匿名类型生成密封类,类名是自动生成的(包含随机字符,避免冲突);
    属性是public readonly,且类型是值类型或引用类型(根据赋值推断);
    重写Equals/GetHashCode/ToString:ToString返回属性名和值的字符串(如{ Name = 张三, Age = 32 })。
  2. 动态对象的常见实现
    ExpandoObject:.NET内置的动态对象,适合动态添加属性(本质是字典);
    DynamicObject:抽象类,可自定义动态对象的行为(如重写TryGetMember/TrySetMember实现属性访问逻辑);
    JObject:Newtonsoft.Json提供的动态对象,用于JSON处理。
  3. 动态对象的性能影响
    动态对象的属性访问是运行时绑定(通过RuntimeBinder),比静态类型慢;
    若需频繁访问动态对象的属性,建议转为静态类型(如用JsonConvert.DeserializeObject);
    适合低频、结构不确定的场景(如JSON反序列化、COM组件调用)。
    扩展思考
    1.匿名类型序列化:System.Text.Json默认不支持匿名类型序列化,如何解决?(提示:用JsonSerializer.Serialize(tempUser, new JsonSerializerOptions { IncludeFields = true })或Newtonsoft.Json);
    2.动态对象转静态类型:如何将动态对象转为已知的实体类?(提示:用JsonConvert.DeserializeObject(JsonConvert.SerializeObject(dynamicUser)));
    3.匿名类型vs元组:匿名类型(var user = new { Name = "张三" })和元组(var user = ("张三",32))的区别?(元组更轻量,支持解构,适合临时传递多个值;匿名类型适合有明确属性名的场景);
    4.自定义动态对象:继承DynamicObject,实现一个能自动转换属性类型的动态对象(如将字符串“123”转为int)。
    总结
    匿名类型和动态对象是C#中处理临时数据的高效工具:
    匿名类型:强类型、只读、性能高,适合结构固定的临时数据;
    动态对象:弱类型、可读写、灵活,适合结构不确定的场景;
    选择原则:优先用匿名类型(类型安全),只有当结构不确定时才用动态对象(注意错误处理)。
    合理使用两者可以减少冗余代码,提高开发效率,但要注意动态对象的类型安全和性能问题。

本站原创,转载请注明出处:


相关教程