利用C#的Type.GetProperty实现高效的数据转换

本文介绍了一种使用管道符(|)分割的数据解析方法,并提供了一个简洁的C#代码示例,展示了如何将管道分隔的数据转换为自定义的类实例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

今天在编程程序时,遇到一个使用“|”分割的数据,需要分割数据解析和组装成指定数据类型。先看这个问题需求场景:

数据是按如下格式组织的,

唯一标示|用户编号|用户名称|…

参数代码

参数说明

primaryKey

收费记录的唯一值,以防重复传输。

consNo

用户编号

consName

用户名称

orgNo

用户单位

rcvOrgNo

收款单位

acctOrgNo

清算单位编码

bankCode

收款机构

rcvAmt

收费金额

rcvedAmt

实收金额(不包含违约金)

rcvedPenalty

实收违约金

prepayAmt

预收金额

acctBal

用户余额(此条记录当时的余额,若无此余额,返回空值)

payDate

收费日期(精确到秒)

typeCode

收费类型(收费、冲正、退费等)

payMode

缴费方式(柜台收费,银行代收等)

settleMode

结算方式(现金,支票等)


实现解析算法:首先定义一个数据结构,由如上各字段组成,代码如下:

[csharp]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. public class PayInfo  
  2. {  
  3.     public string primaryKey { getset; }//收费记录的唯一值,以防重复传输。  
  4.     public string consNo { getset; }//用户编号  
  5.     public string consName { getset; }//用户名称  
  6.     public string orgNo { getset; }//用户单位  
  7.     public string rcvOrgNo { getset; }//收款单位  
  8.     public string acctOrgNo { getset; }//清算单位编码  
  9.     public string bankCode { getset; }//收款机构  
  10.     public string rcvAmt { getset; }//收费金额  
  11.     public string rcvedAmt { getset; }//实收金额(不包含违约金)  
  12.     public string rcvedPenalty { getset; }//实收违约金  
  13.     public string prepayAmt { getset; }//预收金额  
  14.     public string acctBal { getset; }//用户余额(此条记录当时的余额,若无此余额,返回空值)  
  15.     public string payDate { getset; }//收费日期(精确到秒)  
  16.     public string typeCode { getset; }//收费类型(收费、冲正、退费等)  
  17.     public string payMode { getset; }//缴费方式(柜台收费,银行代收等)  
  18.     public string settleMode { getset; }//结算方式(现金,支票等)  
  19. }  

然后将由|组织的数据转换为PayInfo数据,正常的思路是,按顺序解析值,并将值赋给对应的字段,实现的代码将如下:

[csharp]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. string[] strs = value.Split(split, StringSplitOptions.None);  
  2. PayInfo pay = new PayInfo();  
  3. pay.primaryKey = strs[0];  
  4. pay.consNo = strs[1];  
  5. //在下面实现所有字段的赋值操作  
  6. //此处省略相应的代码  
如果对应字段有跟多,全部写完,这个代码很长,读起来都很费劲,写的时候也容易出错。那么能不能让代码简单呢?答案一定是,下面看看如下代码:

[csharp]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. PayInfo pay = new PayInfo();  
  2. string[] split = { "|" };  
  3. string[] strs = value.Split(split, StringSplitOptions.None);  
  4. string[] fileds = {"primaryKey","consNo","consName","orgNo","rcvOrgNo","acctOrgNo","bankCode","rcvAmt","rcvedAmt","rcvedPenalty","prepayAmt","acctBal","payDate","typeCode","payMode","settleMode" };  
  5. for(int i=0;i<strs.Length;i++)  
  6.     pay.GetType().GetProperty (fileds[i]).SetValue(pay, strs[i], null);  

这个只用了6行代码就实现了数据的转换,代码的算法大家一看就明白,下面我简单说一下思路,如上代码主要理由Type.GetProperty方法,实现对C#类属性的赋值。
<think>我们正在处理一个C#问题,用户想要获取PictureBox控件中的私有属性ImageRectangle的信息。根据引用[1],我们看到一个示例代码使用了反射来获取这个私有属性。引用[1]中的代码片段如下: return (Rectangle)_ImageRectanglePropert.GetValue(p_PictureBox, null); 这里假设_ImageRectanglePropert是一个PropertyInfo对象,它指向PictureBox的私有属性ImageRectangle。 因此,我们需要通过反射来获取这个私有属性。步骤如下: 1. 获取PictureBox类型。 2. 使用Type.GetPropertyType.GetField方法,但由于是私有属性,我们需要使用BindingFlags.NonPublic | BindingFlags.Instance来访问非公共的实例成员。 3. 注意:ImageRectangle是一个属性(Property),所以应该使用GetProperty方法,但是它是私有的,所以我们需要指定非公共属性。 但是,在引用[1]中,他们使用了字段(Field)的命名方式(_ImageRectanglePropert),这可能是笔误。实际上,在PictureBox中,ImageRectangle是一个属性(Property),并且是私有的。 根据引用[5],我们知道PictureBox的SizeMode属性会影响ImageRectangle,因为ImageRectangle表示图片在PictureBox中的实际显示区域。 因此,我们可以编写如下代码: 步骤: a. 获取PictureBox的类型。 b. 使用GetProperty方法获取名为"ImageRectangle"的属性,并指定非公共和实例绑定标志。 c. 如果获取成功,则可以通过该PropertyInfo对象来获取具体PictureBox实例的ImageRectangle值。 注意:由于ImageRectangle是私有的,所以我们需要使用反射来访问。 代码示例: 假设我们有一个PictureBox控件pictureBox1,我们想要获取它的ImageRectangle属性值。 我们可以这样写: ```csharp // 获取PictureBox的类型 Type pictureBoxType = typeof(PictureBox); // 获取私有属性ImageRectangle PropertyInfo imageRectangleProperty = pictureBoxType.GetProperty("ImageRectangle", BindingFlags.NonPublic | BindingFlags.Instance); if (imageRectangleProperty != null) { // 获取pictureBox1的ImageRectangle值 Rectangle imageRectangle = (Rectangle)imageRectangleProperty.GetValue(pictureBox1, null); // 现在可以使用imageRectangle } else { // 属性未找到,可能是名称错误或版本问题 } ``` 但是,需要注意的是,私有属性的名称可能会因.NET Framework版本的不同而有所变化。在大多数情况下,这个属性名称是"ImageRectangle"。 另外,引用[1]中的代码也使用了类似的方法,他们用一个字段保存了PropertyInfo,可能是为了避免重复反射带来的性能开销(因为每次获取PropertyInfo都需要反射,而反射是比较耗时的)。 因此,我们可以考虑将PropertyInfo缓存起来,这样在多次获取时效率更高。 例如,我们可以这样: ```csharp private static PropertyInfo _imageRectangleProperty; private static PropertyInfo ImageRectangleProperty { get { if (_imageRectangleProperty == null) { _imageRectangleProperty = typeof(PictureBox).GetProperty("ImageRectangle", BindingFlags.NonPublic | BindingFlags.Instance); } return _imageRectangleProperty; } } // 然后在使用时 if (ImageRectangleProperty != null) { Rectangle rect = (Rectangle)ImageRectangleProperty.GetValue(pictureBox1, null); // ... } ``` 这样,我们只需要在第一次使用时进行反射,后续使用就可以直接获取了。 另外,用户的问题中提到了“私有属性”,所以我们的方法正是针对私有属性的。 但是,需要注意的是,使用反射访问私有成员可能会带来安全性和兼容性问题。在更高版本的.NET中,如果这个属性被移除或改名,代码可能会失效。因此,请确保在必要的场合使用,并做好错误处理。 根据引用[1]的代码,我们也可以看到他们使用了类似的方法,并且返回了一个Rectangle。 因此,我们可以按照上述方法来实现。 最后,我们根据用户的要求,生成相关问题。</think>在 C# 中,通过反射获取 `PictureBox` 的私有属性 `ImageRectangle` 的 `PropertyInfo` 需要以下步骤: ### 实现代码 ```csharp using System.Reflection; using System.Windows.Forms; using System.Drawing; public Rectangle GetPictureBoxImageRectangle(PictureBox pictureBox) { // 1. 获取PictureBox类型 Type pictureBoxType = typeof(PictureBox); // 2. 通过反射获取私有属性ImageRectangle PropertyInfo imageRectangleProperty = pictureBoxType.GetProperty( "ImageRectangle", BindingFlags.NonPublic | BindingFlags.Instance ); // 3. 验证属性是否存在 if (imageRectangleProperty == null) throw new InvalidOperationException("ImageRectangle属性不存在"); // 4. 获取属性值 return (Rectangle)imageRectangleProperty.GetValue(pictureBox, null); } ``` ### 关键说明 1. **反射原理**: - 使用 `BindingFlags.NonPublic` 访问非公共成员 - 使用 `BindingFlags.Instance` 访问实例成员 - 属性名严格匹配 `"ImageRectangle"`(区分大小写) 2. **返回值意义**: - 返回的 `Rectangle` 表示图片在控件中的实际显示区域 - 其值受 `SizeMode` 属性影响(如 `Zoom` 模式会缩放图片)[^5] 3. **性能优化建议**: ```csharp // 缓存PropertyInfo避免重复反射 private static readonly PropertyInfo _cachedProperty = typeof(PictureBox).GetProperty("ImageRectangle", BindingFlags.NonPublic | BindingFlags.Instance); public Rectangle GetImageRectangleFast(PictureBox pb) => (Rectangle)_cachedProperty.GetValue(pb, null); ``` ### 使用示例 ```csharp // 在PictureBox事件中调用 private void pictureBox1_SizeChanged(object sender, EventArgs e) { var rect = GetPictureBoxImageRectangle(pictureBox1); Console.WriteLine($"图片显示区域: {rect}"); } ``` ### 注意事项 1. **安全权限**:需要 `ReflectionPermission` 权限 2. **版本兼容性**:私有属性名在 .NET Framework 4.x 和 .NET Core 3.1+ 中保持一致 3. **空值处理**:当图片未加载时可能返回 `Rectangle.Empty` 4. **坐标系统**:返回的矩形基于控件坐标系(左上角为原点)[^2] > 此方法适用于需要精确获取图片显示区域的场景,如自定义绘制[^3]、坐标转换[^2]或网格叠加[^4]等操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值