当前位置:   article > 正文

C# 反射实现对只读属性进行赋值操作_如何通过反射更改只有get属性的数据

如何通过反射更改只有get属性的数据

需求概述

现用户提出这样个需求,其拿到一个只读属性值(只有get方法,没有set),如何强行修改这个属性的值呢?

这里的属性可以是单值,常见的string,float,double etc,可以是List 对象集合属性。

需求实例

 现对Product下的Id属性和Detail属性值进行修改。

根据对于属性原来的值和属性值类型其存在两种情况:

 1 属性值为空时,单值、List集合操作为均为append追加操作;

 2 属性值不为空,操作分两种:对于单值,进行modify操作;对于多值,需要定位到具体索引,同时可以通过startIndex和length来定位modify操作的长度。

  1. class Product
  2. {
  3. public string Id { get;}//只读,不可写
  4. public string Name { get; set; }
  5. public List<ProductDetail> Detail { get; }//只读,不可写
  6. public List<ProductComment> Comment { get; set; }
  7. }
  8. class ProductDetail
  9. {
  10. public string DtlId { get; set; }
  11. public string Id { get; set; }
  12. public decimal Number { get; set; }
  13. public decimal Price { get; set; }
  14. public decimal Amount { get; set; }
  15. }

实现概述

传入instance对象,在ModifyFieldsValue方法中通过反射获取到指定membername的成员信息。

通过pinfo.CanWrite属性值判断其是否可写,当不可写时,通过newType.GetRuntimeFields()拿到其私有字段值。

调用SetListValueInField方法通过判断MemberInfo具体为PropertyInfo或FieldInfo,来将list数据装载到instance对应的属性上。

 

实现实例

  1. static void Main(string[] args)
  2. {
  3. var instance = new Product();
  4. var DetailListBefore = new List<ProductDetail>
  5. {
  6. new ProductDetail{Id="000" ,DtlId="1",Number=12.3568M,Price=5.689M,Amount=70.2978352M},
  7. new ProductDetail{Id="000",DtlId="2",Number=12.35M,Price=5.689M,Amount=70.2978352M},
  8. new ProductDetail{Id="000",DtlId="3",Number=12.358M,Price=5.689M,Amount=70.304662M},
  9. };
  10. //instance.Detail = DetailListBefore;
  11. var DetailListAfter = new List<ProductDetail>
  12. {
  13. new ProductDetail{Id="111" ,DtlId="4",Number=12.3568M,Price=5.689M,Amount=70.2978352M},
  14. new ProductDetail{Id="111",DtlId="5",Number=12.35M,Price=5.689M,Amount=70.2978352M},
  15. new ProductDetail{Id="111",DtlId="6",Number=12.358M,Price=5.689M,Amount=70.304662M},
  16. };
  17. MethodHelper.ModifyFieldsValue<Product, string>(instance, "Id", "1000");
  18. MethodHelper.ModifyFieldsValue<Product, ProductDetail>(instance, "Detail", null, DetailListAfter, true, 0, 3);
  19. Console.WriteLine(instance.Id);
  20. instance.Detail.ForEach(a => { Console.WriteLine(a.DtlId); });
  21. Console.WriteLine("----------------------------");
  22. Console.ReadKey();
  23. }
  24. //MethodHelper类
  25. /// <summary>
  26. /// 修改实例对应只读或可读写属性的值
  27. /// </summary>
  28. /// <typeparam name="T">实例对象类型</typeparam>
  29. /// <typeparam name="S">属性类型</typeparam>
  30. /// <param name="instance">实例对象</param>
  31. /// <param name="membername">属性名</param>
  32. /// <param name="Singlevalue">赋予的单值</param>
  33. /// <param name="assignlist">赋予的List值</param>
  34. /// <param name="appendOrReplace">对于泛型集合属性,appendOrReplace为true,单值默认为false</param>
  35. /// <param name="StartIndex">>对于泛型集合属性,赋予list新值在原List的StartIndex索引,默认为-1</param>
  36. /// <param name="length">索引长度,默认为0</param>
  37. public static void ModifyFieldsValue<T, S>(T instance, string membername, object Singlevalue = null, List<S> assignlist = null, bool appendOrReplace = false, int StartIndex = -1, int length = 0)
  38. {
  39. var newType = instance.GetType();
  40. var pInfo = newType.GetRuntimeProperties().FirstOrDefault(p => p.Name == membername);
  41. if (pInfo != null && pInfo.CanWrite)
  42. {
  43. if (appendOrReplace)
  44. {
  45. List<S> fVal = (List<S>)pInfo.GetValue(instance);
  46. //原List属性没有值时:
  47. if (fVal == null)
  48. {
  49. SetListValueInField(instance, assignlist, pInfo);
  50. }
  51. //原List属性存在值时:
  52. else
  53. {
  54. AppendOrReplaceList(assignlist, StartIndex, length, fVal);
  55. pInfo.SetValue(instance, fVal);
  56. }
  57. }
  58. else
  59. {
  60. //(S)Convert.ChangeType(Singlevalue, typeof(S))
  61. pInfo.SetValue(instance, Singlevalue);
  62. }
  63. }
  64. else if (pInfo != null)
  65. {
  66. var backFildInfo = newType.GetRuntimeFields().FirstOrDefault(f => f.Name.Contains($"<{membername}>") && f.Name.Contains("BackingField"));
  67. if (appendOrReplace)
  68. {
  69. List<S> fVal = (List<S>)backFildInfo.GetValue(instance);
  70. if (fVal == null)
  71. {
  72. SetListValueInField(instance, assignlist, backFildInfo);
  73. }
  74. else
  75. {
  76. AppendOrReplaceList(assignlist, StartIndex, length, fVal);
  77. }
  78. }
  79. else
  80. {
  81. backFildInfo.SetValue(instance, Singlevalue);
  82. }
  83. }
  84. else
  85. {
  86. return;
  87. }
  88. }
  89. private static void AppendOrReplaceList<S>(List<S> assignlist, int StartIndex, int length, List<S> fVal)
  90. {
  91. if (fVal.Count < length || fVal.Count < assignlist.Count)
  92. {
  93. throw new Exception("传入的length值或assignlist不对,其应小于或等于原集合长度");
  94. }
  95. if (StartIndex != -1 && length > 0)
  96. {
  97. for (int index = 0; index < length; index++)
  98. {
  99. fVal[StartIndex + index] = assignlist[index];
  100. }
  101. }
  102. }
  103. private static void SetListValueInField<T, S>(T instance, List<S> assginlist, MemberInfo pInfo)
  104. {
  105. var type1 = typeof(List<>);
  106. if (pInfo is PropertyInfo)
  107. {
  108. type1 = type1.MakeGenericType((pInfo as PropertyInfo).PropertyType.GenericTypeArguments.First());
  109. object instanceVal = CreateInstanceWithList(assginlist, type1);
  110. (pInfo as PropertyInfo).SetValue(instance, instanceVal);
  111. }
  112. if (pInfo is FieldInfo)
  113. {
  114. type1 = type1.MakeGenericType(((pInfo as FieldInfo)).FieldType.GenericTypeArguments.First());
  115. object instanceVal = CreateInstanceWithList(assginlist, type1);
  116. (pInfo as FieldInfo).SetValue(instance, instanceVal);
  117. }
  118. }
  119. private static object CreateInstanceWithList<S>(List<S> assginlist, Type type1)
  120. {
  121. var instanceVal = Activator.CreateInstance(type1);
  122. var add = type1.GetMethod("Add", type1.GetGenericArguments());
  123. foreach (var obj in assginlist)
  124. {
  125. List<object> parametersList = new List<object>();
  126. parametersList.Add(obj);
  127. add.Invoke(instanceVal, parametersList.ToArray());
  128. }
  129. return instanceVal;
  130. }

 

 
本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号