C# 反射实现对只读属性进行赋值操作

需求概述

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

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

需求实例

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

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

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

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

	class Product
	{
		public string Id { get;}//只读,不可写
		public string Name { get; set; }
		public List<ProductDetail> Detail { get; }//只读,不可写

		public List<ProductComment> Comment { get; set; }
	}
	class ProductDetail
	{
		public string DtlId { get; set; }
		public string Id { get; set; }
		public decimal Number { get; set; }
		public decimal Price { get; set; }
		public decimal Amount { get; set; }
	}

实现概述

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

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

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

 

实现实例

	static void Main(string[] args)
		{
			var instance = new Product();
			var DetailListBefore = new List<ProductDetail>
				{
					new ProductDetail{Id="000" ,DtlId="1",Number=12.3568M,Price=5.689M,Amount=70.2978352M},
					new ProductDetail{Id="000",DtlId="2",Number=12.35M,Price=5.689M,Amount=70.2978352M},
					new ProductDetail{Id="000",DtlId="3",Number=12.358M,Price=5.689M,Amount=70.304662M},
				};
			//instance.Detail = DetailListBefore;

			var DetailListAfter = new List<ProductDetail>
				{
					new ProductDetail{Id="111" ,DtlId="4",Number=12.3568M,Price=5.689M,Amount=70.2978352M},
					new ProductDetail{Id="111",DtlId="5",Number=12.35M,Price=5.689M,Amount=70.2978352M},
					new ProductDetail{Id="111",DtlId="6",Number=12.358M,Price=5.689M,Amount=70.304662M},
				};
			MethodHelper.ModifyFieldsValue<Product, string>(instance, "Id", "1000");
			MethodHelper.ModifyFieldsValue<Product, ProductDetail>(instance, "Detail", null, DetailListAfter, true, 0, 3);
			Console.WriteLine(instance.Id);

			instance.Detail.ForEach(a => { Console.WriteLine(a.DtlId); });
			Console.WriteLine("----------------------------");
			Console.ReadKey();
       }

        //MethodHelper类
        /// <summary>
		/// 修改实例对应只读或可读写属性的值
		/// </summary>
		/// <typeparam name="T">实例对象类型</typeparam>
		/// <typeparam name="S">属性类型</typeparam>
		/// <param name="instance">实例对象</param>
		/// <param name="membername">属性名</param>
		/// <param name="Singlevalue">赋予的单值</param>
		/// <param name="assignlist">赋予的List值</param>
		/// <param name="appendOrReplace">对于泛型集合属性,appendOrReplace为true,单值默认为false</param>
		/// <param name="StartIndex">>对于泛型集合属性,赋予list新值在原List的StartIndex索引,默认为-1</param>
		/// <param name="length">索引长度,默认为0</param>
		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)
		{
			var newType = instance.GetType();
			var pInfo = newType.GetRuntimeProperties().FirstOrDefault(p => p.Name == membername);
			if (pInfo != null && pInfo.CanWrite)
			{
				if (appendOrReplace)
				{
					List<S> fVal = (List<S>)pInfo.GetValue(instance);
					//原List属性没有值时:
					if (fVal == null)
					{
						SetListValueInField(instance, assignlist, pInfo);
					}
					//原List属性存在值时:
					else
					{
						AppendOrReplaceList(assignlist, StartIndex, length, fVal);
						pInfo.SetValue(instance, fVal);
					}
				}
				else
				{
					//(S)Convert.ChangeType(Singlevalue, typeof(S))
					pInfo.SetValue(instance, Singlevalue);
				}
			}
			else if (pInfo != null)
			{
				var backFildInfo = newType.GetRuntimeFields().FirstOrDefault(f => f.Name.Contains($"<{membername}>") && f.Name.Contains("BackingField"));
				if (appendOrReplace)
				{
					List<S> fVal = (List<S>)backFildInfo.GetValue(instance);
					if (fVal == null)
					{
						SetListValueInField(instance, assignlist, backFildInfo);
					}
					else
					{
						AppendOrReplaceList(assignlist, StartIndex, length, fVal);
					}
				}
				else
				{
					backFildInfo.SetValue(instance, Singlevalue);
				}
			}
			else
			{
				return;
			}

		}

		private static void AppendOrReplaceList<S>(List<S> assignlist, int StartIndex, int length, List<S> fVal)
		{
			if (fVal.Count < length || fVal.Count < assignlist.Count)
			{
				throw new Exception("传入的length值或assignlist不对,其应小于或等于原集合长度");
			}
			if (StartIndex != -1 && length > 0)
			{
				for (int index = 0; index < length; index++)
				{
					fVal[StartIndex + index] = assignlist[index];
				}
			}
		}

		private static void SetListValueInField<T, S>(T instance, List<S> assginlist, MemberInfo pInfo)
		{
			var type1 = typeof(List<>);
			if (pInfo is PropertyInfo)
			{
				type1 = type1.MakeGenericType((pInfo as PropertyInfo).PropertyType.GenericTypeArguments.First());
				object instanceVal = CreateInstanceWithList(assginlist, type1);
				(pInfo as PropertyInfo).SetValue(instance, instanceVal);
			}
			if (pInfo is FieldInfo)
			{
				type1 = type1.MakeGenericType(((pInfo as FieldInfo)).FieldType.GenericTypeArguments.First());
				object instanceVal = CreateInstanceWithList(assginlist, type1);
				(pInfo as FieldInfo).SetValue(instance, instanceVal);
			}
		}

		private static object CreateInstanceWithList<S>(List<S> assginlist, Type type1)
		{
			var instanceVal = Activator.CreateInstance(type1);
			var add = type1.GetMethod("Add", type1.GetGenericArguments());
			foreach (var obj in assginlist)
			{
				List<object> parametersList = new List<object>();
				parametersList.Add(obj);
				add.Invoke(instanceVal, parametersList.ToArray());
			}
			return instanceVal;
		}

 

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值