一、值类型和引用类型
值类型:
包含类型:数值类型、结构体、bool类型、枚举、可空类型(例如:int、double、bool、char、decimal、struct、enum)等等。
存储特征:数据保存在栈中
引用类型:
包含的类型:数组、委托、接口、object、集合、字符串、用户自定义的类等等。
存储特征:数据保存在堆中,并在栈里有一个对堆内数据引用
二、传递方式
按值传递:所有的类型默认是按值传递的。
值类型传递给方法,会在栈中克隆出一份相同的数据。方法内对数据的更改不会影响方法外的数据
引用类型传递给方法,会将现有栈中的引用传入方法内,不会增加新数据。方法内对数据的更改会影响方法外的数据,但如果进行了new()操作重新赋值,则会在堆和栈中生成一份新的数据,后续方法内对数据的更新,不会影响方法外的数据
按引用传递:通过使用ref 、out 关键词,可以对类型按引用传递。对类型实例的所有改动都将影响现有数据
三、通过原理看bug
1、合理使用按值传递避免bug
下面这段代码,couponState是枚举,属于值类型,如果在某次循环中对入参couponState做了修改,则后面的循环中即便不没有对couponState做修改,也无法获得刚进入方法时couponState的值了,因为couponState的值已被修改了
1 private static void UpdateCouponCache(List<GetUserCouponToFcpDto> filterFcp, CouponStateEnum couponState, int operatorTag) 2 { 3 foreach (GetUserCouponToFcpDto item in filterFcp) 4 { 5 foreach (CouponChangeDto coupon in item.CouponList) 6 { 7 UserReceivedCouponEntity couponEntity = GetUserCompanyCouponInfo(item.CustomerId, coupon.OwnerId, coupon.Id); 8 if (couponEntity == null || string.IsNullOrEmpty(couponEntity.Id)) 9 { 10 continue; 11 } 12 if (operatorTag != 0) 13 { 14 couponEntity.SurplusCouponAmount += coupon.UesdAmount * operatorTag; 15 } 16 if (couponEntity.SurplusCouponAmount < 0) 17 { 18 couponEntity.SurplusCouponAmount = 0; 19 } 20 if (couponEntity.SurplusCouponAmount > couponEntity.CouponAmount) 21 { 22 couponEntity.SurplusCouponAmount = couponEntity.CouponAmount; 23 } 24 if (couponState != CouponStateEnum.Freezed) 25 { 26 if (couponEntity.SurplusCouponAmount == 0) 27 { 28 couponState = CouponStateEnum.Used; 29 } 30 if (couponEntity.SurplusCouponAmount == couponEntity.CouponAmount) 31 { 32 couponState = CouponStateEnum.NotUsed; 33 } 34 if (couponState == CouponStateEnum.PartialUse) 35 { 36 if (couponEntity.IsCanUseMultipleTimes == "1" && operatorTag < 0) 37 { 38 couponState = CouponStateEnum.Used; 39 } 40 } 41 } 42 couponEntity.CouponState = (int)couponState; 43 } 44 }45 }
解决方法:通过对循环内的方法提取子方法,couponState按值传递,可以保证后续的循环仍可获得方法入参刚进入方法时couponState的值
1 private static void UpdateCouponCache(List<GetUserCouponToFcpDto> filterFcp, CouponStateEnum couponState, int operatorTag) 2 { 3 foreach (GetUserCouponToFcpDto item in filterFcp) 4 { 5 foreach (CouponChangeDto coupon in item.CouponList) 6 { 7 UserReceivedCouponEntity couponEntity = GetUserCompanyCouponInfo(item.CustomerId, coupon.OwnerId, coupon.Id); 8 if (couponEntity == null || string.IsNullOrEmpty(couponEntity.Id)) 9 { 10 continue; 11 } 12 UpdateCouponInfo(couponState, operatorTag, item, coupon, couponEntity); 13 } 14 } 15 } 16 17 private static void UpdateCouponInfo(CouponStateEnum couponState, int operatorTag, GetUserCouponToFcpDto item, CouponChangeDto coupon, UserReceivedCouponEntity couponEntity) 18 { 19 if (operatorTag != 0) 20 { 21 couponEntity.SurplusCouponAmount += coupon.UesdAmount * operatorTag; 22 } 23 if (couponEntity.SurplusCouponAmount < 0) 24 { 25 couponEntity.SurplusCouponAmount = 0; 26 } 27 if (couponEntity.SurplusCouponAmount > couponEntity.CouponAmount) 28 { 29 couponEntity.SurplusCouponAmount = couponEntity.CouponAmount; 30 } 31 if (couponState != CouponStateEnum.Freezed) 32 { 33 if (couponEntity.SurplusCouponAmount == 0) 34 { 35 couponState = CouponStateEnum.Used; 36 } 37 if (couponEntity.SurplusCouponAmount == couponEntity.CouponAmount) 38 { 39 couponState = CouponStateEnum.NotUsed; 40 } 41 if (couponState == CouponStateEnum.PartialUse) 42 { 43 if (couponEntity.IsCanUseMultipleTimes == "1" && operatorTag < 0) 44 { 45 couponState = CouponStateEnum.Used; 46 } 47 } 48 } 49 couponEntity.CouponState = (int)couponState; 50 }
2、合理使用按引用传递避免bug
下面这段代码中,matchBusLine是引用类型,采用按值传递的方式传递给了方法InitMatchDayBusClassesNotForBack,InitMatchDayBusClassesNotForBack内在特定条件下对matchBusLine进行重新new()的操作,因为采用值传递,new()操作新增了一份数据,不会传递到方法外
解决方法:给matchBusLine这个参数增加ref关键词,采用按引用传递的方式,从而将方法内的更新传递到方法外
标签:coupon,CouponStateEnum,couponState,传递,引用,couponEntity,SurplusCouponAmount From: https://www.cnblogs.com/lianjinzhe/p/16989076.html