C#中的映射

 

C#编译后的文件主要由IL代码和元数据组成,元数据为.NET组件提供了丰富的自描述特性,它使得我们可以在代码运行时获知组件中的类型等重要的信息。C#中这是通过一种称作映射(Reflection)的机制来完成的。

动态类型查询

首先创建一个简单的类型:

namespace ReflectionClass

{

    public class MyClass

    {

        #region Property

        private int m_Count = 100;

        public int Count

        {

            get

            {

                return m_Count;

            }

            set

            {

                m_Count = value;

            }

        }

        #endregion

 

        #region Method

        public void Print()

        {

            Console.WriteLine("MyClass.Count = {}"Count);

        }

        #endregion

}

}

编译后可以得到“ReflectionClass.dll”文件,接下来实现查询类型的测试程序:

namespace TestReflection

{

    public class App

    {

        static void Main(string[] args)

        {

            Type type = typeof(MyClass); //获取MyClass的类型信息

            Console.WriteLine("The Type Name : {0}"type.Name); //获取类型的名字

 

            FieldInfo[] fieldArray = type.GetFields(); //获取所有的公有域

            Console.Write("The {0} Fields : "fieldArray.Length);

            foreach (FieldInfo field in fieldArray)

            {

                Console.Write(field.Name + " ");

            }

            Console.WriteLine();

            PropertyInfo[] propertyArray = type.GetProperties(); //获取所有的公有属性

            Console.Write("The {0} Properties : "propertyArray.Length);

            foreach (PropertyInfo property in propertyArray)

            {

                Console.Write(property.Name + " ");

            }

            Console.WriteLine();

            MethodInfo[] methodArray = type.GetMethods(); //获取所有的公有方法

            Console.Write("The {0} Methods : "methodArray.Length);

            foreach (MethodInfo method in methodArray)

            {

                Console.Write(method.Name + " ");

            }

        }

    }

}

编译后执行,可以得到以下输出:

The Type Name : MyClass

The 0 Fields :

The 1 Properties : Count

The 7 Methods : get_Count set_Count Print ToString Equals GetHashCode GetType

在上面的例子中,首先通过 typeof(MyClass)获得MyClass类的类型信息,当然也可以通过创建对象实例,然后调用对象实例的GetType方法来获得(每个类都从 object根类中继承获得此方法)。在拥有了类型信息(变量type)后,便可以获得其类型的名字、该类型含有的公有域、公有属性、公有方法。注意: 这里C#的映射机制只允许获取类型的公有信息,这符合面向对象的封装原则。其中4个方法(GetHashCode、Equals、ToString、GetType)都是继承自object类的公有方法,而方法get_Count 和set_Count则是实现Count属性的“副产物。实际上,System.Type类各种各样的成员使得我们能够获得几乎所有与类型相关的公有信息。在System.Reflection命名空间下的各个类都可以获得各个编程元素较详细的信息,如方法的参数与返回值、域的类型、枚举的各个值等。

动态创建与调用

实际上映射远不止动态地获知组件的类型信息,它还能在获得类型信息的基础上,在代码运行时进行类型的动态创建与方法的动态调用。

namespace TestReflection2

{

    public class App

    {

        static void Main(string[] args)

        {

            Assembly assemlby = Assembly.LoadFrom("ReflectionClass.dll"); //装载组件

            foreach (var type in assemlby.GetTypes())

            {

                if (type.IsClass && !type.IsAbstract)

                {

                    MethodInfo[] methodArray = type.GetMethods(); //获得类型的公有方法

                    object obj = Activator.CreateInstance(type); //创建实例(无参构造器)

                    foreach (var method in methodArray)

                    {

                        if (!method.IsAbstract && !method.IsStatic && method.GetParameters().Length == 0)

                        {

                            object ret = method.Invoke(objnull); //调用实例方法

                            Console.WriteLine("{0}'s Return : {1}"method.Nameret);

                        }

                    }

                }

            }

        }

    }

}

编译后执行,可以得到以下输出:

get_Count's Return : 100

MyClass.Count = 100

Print's Return :

ToString's Return : ReflectionClass.MyClass

GetHashCode's Return : 62476613

GetType's Return : ReflectionClass.MyClass

在上面的例子中给出了被动态调用的方法名字和返回值。其中第二行输出的“MyClass.Count = 100”,它是动态调用方法MyClass.Print()的输出。需要指出的是调用的是类型的公有无参数实例方法。给出组件的名字,应用Assembly.LoadFrom,我们便可以动态地装载组件。 Activator.CreateInstance()允许动态地创建类型(这里只通过无参数的构造器来创建),实际上用它创建出来的类型和用“MyClass obj = new MyClass()”创建出来的类型一样。进而,还可以在查询到的成员的基础上,对它们进行动态调用。

另外,还可以用“Assembly.CreateInstance()”创建实例,从本质上讲,“Assembly.CreateInstance()”就是调用的“Activator.CreateInstance()”。

 

http://www.cnblogs.com/xirihanlin/archive/2009/01/11/1373789.html

<think>首先,用户的问题是关于C#中的映射概念或实现方法,具体是“C#映射实现及用法”。我需要根据系统级指令来构建回答。系统级指令:-所有行内数学表达式使用$...$格式。-独立公式使用$$...$$格式并单独成段。-LaTeX语法正确。-使用中文回答。-生成相关问题。-回答中引用的段落末尾自然地添加引用标识,例如:[^1]-回答结构清晰,帮助用户逐步解决问题,尽量保证回答真实可靠。-参考站内引用:有三个引用[^1],[^2],[^3],但它们是示例性的,我需要基于用户的问题来回答。用户的问题是关于C#中的映射,这可能有几种含义:-对象映射:如将数据库实体映射到视图模型。-URL映射:如短网址映射。-反射:用于动态访问属性。从提供的引用看:-引用[^1]展示了反射的使用,用于动态获取对象的属性。-引用[^2]讨论了对象映射,包括使用JSON序列化和AutoMapper。-引用[^3]是关于短网址映射算法的实现。所以,我应该覆盖这些方面:对象映射(包括反射、AutoMapper)、URL映射(短网址)。回答结构:1.**介绍映射概念**:解释C#映射的含义。2.**对象映射的实现方法**:-使用反射(如引用[^1])。-使用JSON序列化(如引用[^2])。-使用AutoMapper(如引用[^2]提到)。3.**URL映射的实现方法**:-短网址映射(如引用[^3])。4.**用法示例**:提供代码示例。5.**生成相关问题**:在末尾添加相关问题。确保回答清晰、逐步:-先定义映射。-然后分点解释不同实现方法。-提供代码片段。-引用参考。数学表达式:用户的问题没有明显数学内容,但系统指令说所有行内数学表达式必须用$...$。如果有涉及数学的,比如在算法中,我应该用LaTeX格式。但在C#映射中,可能不涉及数学,所以可能不需要。如果有,比如在短网址算法中,如果涉及哈希函数,我可以用数学表示。例如,短网址映射可能使用哈希函数,如$h(x)=(x\timesp)\modm$,但我需要确保相关。引用标识:在回答中,当我提到参考内容时,在段落末尾添加[^1],[^2],[^3]。生成相关问题:在末尾添加3-5个相关问题。语言:中文。现在,规划回答:1.**引言**:解释映射C#中的含义。2.**对象映射**:-反射方法。-JSON序列化方法。-AutoMapper方法。3.**URL映射**:-短网址映射。4.**总结**。5.**相关问题**。代码示例:-反射:如引用[^1]。-JSON:使用Newtonsoft.Json或System.Text.Json。-AutoMapper:配置映射。-短网址:简单实现。确保LaTeX正确:如果有数学,比如在短网址算法中,使用$...$。例如,短网址算法可能涉及哈希函数:$\text{hash}=\text{base62}(\text{id})$。最终回答结构:-清晰段落。-代码块用```csharp```。-引用标识。</think>### C# 中的映射实现及用法详解 在 C# 中,“映射”通常指将一种数据结构或对象转换为另一种形式,常见于对象映射(如数据库实体到视图模型)和 URL 映射(如短网址算法)。映射的核心目的是简化数据转换、提高代码复用性和性能。下面我将逐步解释实现方法、用法示例和注意事项,确保回答真实可靠(基于 C# 官方文档和常见实践)。 #### 1. **映射概念概述** - **对象映射**:将一个对象的属性值复制到另一个对象中,常用于数据层到 UI 层的转换(如将数据库实体映射到 DTO)。 - **URL 映射**:将长网址转换为短网址,用于节省空间和提升用户体验。 - **反射映射**:通过反射动态访问对象的属性,实现灵活的数据处理。 这些方法在性能、易用性和场景适用性上各有优势[^1][^2][^3]。 #### 2. **对象映射的实现方法** 对象映射C# 中最常见的映射需求,以下是三种主流实现方式,各有适用场景。 **a. 使用反射实现映射** 反射允许在运行时动态获取对象属性,适用于需要高度灵活的映射(如处理未知属性)。示例基于引用[^1]: ```csharp // 示例:将对象属性映射到字典,排除特定字段 var re = Db.Queryable<V_DLMiniStation>().Where(it => it.g1 == id).Select(it => new { it.ID, it.Lat, it.Long, it.Master, it.sLevel, it.sName, it.Address, it.Tel }).ToList(); var res = re.Select(a => { Dictionary<string, string> tmp = new Dictionary<string, string>(); foreach (System.Reflection.PropertyInfo p in a.GetType().GetProperties()) { if (p.Name != "Lat" && p.Name != "Long" && p.Name != "ID") { tmp.Add(p.Name, p.GetValue(a)?.ToString()); // 安全处理空值 } } return new { lng = a.Long, lat = a.Lat, id = a.ID, info = tmp.Select(di => new { name = di.Key, value = di.Value }) }; }); // 输出:每个对象包含经纬度、ID 和动态属性字典 ``` - **优点**:无需预定义映射规则,适合动态数据结构。 - **缺点**:性能较低(反射操作较慢),不适合高并发场景。 - **用法**:适用于日志处理、动态表单或 ORM 框架中的数据转换[^1]。 **b. 使用 JSON 序列化实现映射** 通过 JSON 库(如 Newtonsoft.Json 或 System.Text.Json)序列化和反序列化对象,实现快速映射。示例基于引用[^2]: ```csharp using Newtonsoft.Json; // 安装 NuGet 包 Newtonsoft.Json // 定义源和目标类 public class Source { public int Id { get; set; } public string Name { get; set; } } public class Target { public int Id { get; set; } public string Name { get; set; } } // 映射方法:序列化源对象,再反序列化到目标对象 Source source = new Source { Id = 1, Name = "Test" }; string json = JsonConvert.SerializeObject(source); // 序列化为 JSON 字符串 Target target = JsonConvert.DeserializeObject<Target>(json); // 反序列化到目标类型 // 输出:target.Id = 1, target.Name = "Test" ``` - **优点**:简单易用,支持嵌套对象和集合。 - **缺点**:序列化开销大,可能不适用于高性能场景。 - **用法**:适合 API 数据传输、配置加载或简单对象转换[^2]。 **c. 使用 AutoMapper 实现映射** AutoMapper 是流行的对象映射库,通过预配置规则提升性能。示例基于引用[^2]: ```csharp using AutoMapper; // 安装 NuGet 包 AutoMapper // 定义映射配置 var config = new MapperConfiguration(cfg => { cfg.CreateMap<Source, Target>(); // 源到目标的映射规则 }); IMapper mapper = config.CreateMapper(); // 执行映射 Source source = new Source { Id = 1, Name = "Test" }; Target target = mapper.Map<Target>(source); // 直接映射 // 输出:target.Id = 1, target.Name = "Test" ``` - **优点**:高性能(基于表达式树编译),支持复杂规则(如忽略属性)。 - **缺点**:需要初始配置,学习曲线较陡。 - **用法**:推荐用于 MVC 应用、数据库查询结果映射[^2]。 #### 3. **URL 映射的实现方法** URL 映射常用于短网址服务,其核心是将长网址通过哈希算法转换为短码(如 6 位字符串)。算法通常基于哈希函数和进制转换。示例基于引用[^3]: ```csharp using System.Security.Cryptography; // 短网址映射算法:使用 MD5 哈希和 Base62 编码 public class ShortUrlMapper { public static string GenerateShortUrl(string longUrl) { using (MD5 md5 = MD5.Create()) { byte[] hash = md5.ComputeHash(System.Text.Encoding.UTF8.GetBytes(longUrl)); // 取哈希前 4 字节并转换为 uint uint num = BitConverter.ToUInt32(hash, 0); // Base62 编码(62 进制:0-9, a-z, A-Z) string base62 = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; string shortCode = ""; while (num > 0) { shortCode = base62[(int)(num % 62)] + shortCode; // 取模运算 num /= 62; } return shortCode.PadLeft(6, '0'); // 补位到 6 位 } } } // 用法:将长网址映射为短码 string shortUrl = ShortUrlMapper.GenerateShortUrl("https://example.com/long/url"); // 输出:类似 "a1B2c3" ``` - **算法解释**:哈希函数(如 MD5 或 SHA256)将长网址映射到固定长度值,再通过 Base62 编码缩短。数学上,这等价于计算: $$ \text{shortCode} = \text{base62}\left( \text{hash}(\text{longUrl}) \mod 62^k \right) $$ 其中 $k$ 是短码长度(默认 6),$\mod$ 表示取模运算。 - **优点**:URL 长度显著缩短,易于存储和分享。 - **缺点**:需处理哈希冲突(概率低但存在)。 - **用法**:适用于社交媒体链接、二维码生成或 API 网关[^3]。 #### 4. **关键注意事项** - **性能对比**:反射映射最灵活但最慢(时间复杂度 $O(n)$ 属性访问),AutoMapper 最快(接近 $O(1)$ 编译后),JSON 序列化适中。 - **错误处理**:反射中需检查 `GetValue` 空值;AutoMapper 需验证配置;短网址算法应添加唯一性检查。 - **适用场景**: - 反射:动态数据绑定(如 ORM)。 - JSON:跨平台数据交换。 - AutoMapper:大型项目对象转换。 - URL 映射:Web 服务优化。 - **工具推荐**: - AutoMapper:用于复杂对象映射。 - System.Text.Json:内置高性能 JSON 序列化。 - 哈希算法库(如 System.Security.Cryptography):用于 URL 映射。 #### 5. **总结** C# 中的映射实现多样,对象映射优先使用 AutoMapper 或 JSON 序列化以平衡性能和易用性;URL 映射依赖哈希算法。反射提供底层灵活性但需谨慎使用。实际开发中,结合需求选择合适方法,能显著提升代码质量和效率[^1][^2][^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值