25种代码坏味道总结+优化示例

前言

什么样的代码是好代码呢?好的代码应该命名规范、可读性强、扩展性强、健壮性......而不好的代码又有哪些典型特征呢?这25种代码坏味道大家要注意啦

1. Duplicated Code (重复代码)

重复代码就是不同地点,有着相同的程序结构。一般是因为需求迭代比较快,开发小伙伴担心影响已有功能,就复制粘贴造成的。重复代码很难维护的,如果你要修改其中一段的代码逻辑,就需要修改多次,很可能出现遗漏的情况。

如何优化重复代码呢?分三种情况讨论:

  1. 同一个类的两个函数含有相同的表达式

class A {public void method1() {doSomething1doSomething2doSomething3}public void method2() {doSomething1doSomething2doSomething4}
}

优化手段:可以使用Extract Method(提取公共函数) 抽出重复的代码逻辑,组成一个公用的方法。

class A {public void method1() {commonMethod();doSomething3}public void method2() {commonMethod();doSomething4}public void commonMethod(){doSomething1doSomething2}
}
  1. 两个互为兄弟的子类内含相同的表达式

class A extend C {public void method1() {doSomething1doSomething2doSomething3}
}class B extend C {public void method1() {doSomething1doSomething2doSomething4}
}

优化手段:对两个类都使用Extract Method(提取公共函数),然后把抽取出来的函数放到父类中。

class C {public void commonMethod(){doSomething1doSomething2}
}
class A extend C {public void method1() {commonMethod();doSomething3}
}class B extend C {public void method1() {commonMethod();doSomething4}
}
  1. 两个毫不相关的类出现重复代码

如果是两个毫不相关的类出现重复代码,可以使用Extract Class将重复代码提炼到一个类中。这个新类可以是一个普通类,也可以是一个工具类,看具体业务怎么划分吧。

2 .Long Method (长函数)

长函数是指一个函数方法几百行甚至上千行,可读性大大降低,不便于理解。反例如下:

public class Test {private String name;private Vector<Order> orders = new Vector<Order>();public void printOwing() {//print bannerSystem.out.println("****************");System.out.println("*****customer Owes *****");System.out.println("****************");//calculate totalAmountEnumeration env = orders.elements();double totalAmount = 0.0;while (env.hasMoreElements()) {Order order = (Order) env.nextElement();totalAmount += order.getAmout();}//print detailsSystem.out.println("name:" + name);System.out.println("amount:" + totalAmount);......}
}

可以使用Extract Method,抽取功能单一的代码段,组成命名清晰的小函数,去解决长函数问题,正例如下:

public class Test {private String name;private Vector<Order> orders = new Vector<Order>();public void printOwing() {//print bannerprintBanner();//calculate totalAmountdouble totalAmount = getTotalAmount();//print detailsprintDetail(totalAmount);}void printBanner(){System.out.println("****************");System.out.println("*****customer Owes *****");System.out.println("****************");}double getTotalAmount(){Enumeration env = orders.elements();double totalAmount = 0.0;while (env.hasMoreElements()) {Order order = (Order) env.nextElement();totalAmount += order.getAmout();}return totalAmount;}void printDetail(double totalAmount){System.out.println("name:" + name);System.out.println("amount:" + totalAmount);}}

3.  Large Class (过大的类)

一个类做太多事情,维护了太多功能,可读性变差,性能也会下降。举个例子,订单相关的功能你放到一个类A里面,商品库存相关的也放在类A里面,积分相关的还放在类A里面...反例如下:

Class A{public void printOrder(){System.out.println("订单");}public void printGoods(){System.out.println("商品");}public void printPoints(){System.out.println("积分");}
}

试想一下,乱七八糟的代码块都往一个类里面塞,还谈啥可读性。应该按单一职责,使用Extract Class把代码划分开,正例如下:

Class Order{public void printOrder(){System.out.println("订单");}
}Class Goods{public void printGoods(){System.out.println("商品");}
}Class Points{   public void printPoints(){System.out.println("积分");}}
}

4. Long Parameter List (过长参数列)

方法参数数量过多的话,可读性很差。如果有多个重载方法,参数很多的话,有时候你都不知道调哪个呢。并且,如果参数很多,做新老接口兼容处理也比较麻烦。

public void getUserInfo(String name,String age,String sex,String mobile){// do something ...
}

如何解决过长参数列问题呢?将参数封装成结构或者类,比如我们将参数封装成一个DTO类,如下:

public void getUserInfo(UserInfoParamDTO userInfoParamDTO){// do something ...
}class UserInfoParamDTO{private String name;private String age; private String sex;private String mobile;
}

5. Divergent Change (发散式变化)

对程序进行维护时, 如果添加修改组件, 要同时修改一个类中的多个方法, 那么这就是 Divergent Change。举个汽车的例子,某个汽车厂商生产三种品牌的汽车:BMW、Benz和LaoSiLaiSi,每种品牌又可以选择燃油、纯电和混合动力。反例如下

/***  公众号:捡田螺的小男孩*/
public class Car {private String name;void start(Engine engine) {if ("HybridEngine".equals(engine.getName())) {System.out.println("Start Hybrid Engine...");} else if ("GasolineEngine".equals(engine.getName())) {System.out.println("Start Gasoline Engine...");} else if ("ElectricEngine".equals(engine.getName())) {System.out.println("Start Electric Engine");}}void drive(Engine engine,Car car) {this.start(engine);System.out.println("Drive " + getBrand(car) + " car...");}String getBrand(Car car) {if ("Baoma".equals(car.getName())) {return "BMW";} else if ("BenChi".equals(car.getName())) {return "Benz";} else if ("LaoSiLaiSi".equals(car.getName())) {return "LaoSiLaiSi";}return null;}}

如果新增一种品牌新能源电车,然后它的启动引擎是核动力呢,那么就需要修改Car类的startgetBrand方法啦,这就是代码坏味道:Divergent Change (发散式变化)

如何优化呢?一句话总结:拆分类,将总是一起变化的东西放到一块

  • 运用提炼类(Extract Class) 拆分类的行为。

  • 如果不同的类有相同的行为,提炼超类(Extract Superclass) 和 提炼子类(Extract Subclass)。

正例如下:

因为Engine是独立变化的,所以提取一个Engine接口,如果新加一个启动引擎,多一个实现类即可。如下:

//IEngine
public interface IEngine {void start();
}public class HybridEngineImpl implements IEngine { @Overridepublic void start() {System.out.println("Start Hybrid Engine...");}
}

因为drive方法依赖于Car,IEngine,getBand方法;getBand方法是变化的,也跟Car是有关联的,所以可以搞个抽象Car的类,每个品牌汽车继承于它即可,如下

public abstract class AbstractCar {protected IEngine engine;public AbstractCar(IEngine engine) {this.engine = engine;}public abstract void drive();
}//奔驰汽车
public class BenzCar extends AbstractCar {public BenzCar(IEngine engine) {super(engine);}@Overridepublic void drive() {this.engine.start();System.out.println("Drive " + getBrand() + " car...");}private String getBrand() {return "Benz";}
}//宝马汽车
public class BaoMaCar extends AbstractCar {public BaoMaCar(IEngine engine) {super(engine);}@Overridepublic void drive() {this.engine.start();System.out.println("Drive " + getBrand() + " car...");}private String getBrand() {return "BMW";}
}

细心的小伙伴,可以发现不同子类BaoMaCar和BenzCar的drive方法,还是有相同代码,所以我们可以再扩展一个抽象子类,把drive方法推进去,如下:

public abstract class AbstractRefinedCar extends AbstractCar {public AbstractRefinedCar(IEngine engine) {super(engine);}@Overridepublic void drive() {this.engine.start();System.out.println("Drive " + getBrand() + " car...");}abstract String getBrand();
}//宝马
public class BaoMaRefinedCar extends AbstractRefinedCar {public BaoMaRefinedCar(IEngine engine) {super(engine);}@OverrideString getBrand() {return  "BMW";}
}

如果再添加一个新品牌,搞个子类,继承AbstractRefinedCar即可,如果新增一种启动引擎,也是搞个类实现IEngine接口即可

6. Shotgun Surgery(散弹式修改)

当你实现某个小功能时,你需要在很多不同的类做出小修改。这就是Shotgun Surgery(散弹式修改)。它跟发散式变化(Divergent Change) 的区别就是,它指的是同时对多个类进行单一的修改,发散式变化指在一个类中修改多处。反例如下

public class DbAUtils {@Value("${db.mysql.url}")private String mysqlDbUrl;...
}public class DbBUtils {@Value("${db.mysql.url}")private String mysqlDbUrl;...
}

多个类使用了db.mysql.url这个变量,如果将来需要切换mysql到别的数据库,如Oracle,那就需要修改多个类的这个变量!

如何优化呢?将各个修改点,集中到一起,抽象成一个新类。

可以使用 Move Method (搬移函数)和 Move Field (搬移字段)把所有需要修改的代码放进同一个类,如果没有合适的类,就去new一个。

正例如下:

public class DbUtils {@Value("${db.mysql.url}")private String mysqlDbUrl;...
}

7. Feature Envy (依恋情节)

某个函数为了计算某个值,从另一个对象那里调用几乎半打的取值函数。通俗点讲,就是一个函数使用了大量其他类的成员,有人称之为红杏出墙的函数。反例如下:

public class User{private Phone phone;public User(Phone phone){this.phone = phone;}public void getFullPhoneNumber(Phone phone){System.out.println("areaCode:" + phone.getAreaCode());System.out.println("prefix:" + phone.getPrefix());System.out.println("number:" + phone.getNumber());}
}

如何解决呢?在这种情况下,你可以考虑将这个方法移动到它使用的那个类中。例如,要将 getFullPhoneNumber()User 类移动到Phone类中,因为它调用了Phone类的很多方法。

8. Data Clumps(数据泥团)

数据项就像小孩子,喜欢成群结队地呆在一块。如果一些数据项总是一起出现的,并且一起出现更有意义的,就可以考虑,按数据的业务含义来封装成数据对象。反例如下:

public class User {private String firstName;private String lastName;private String province;private String city;private String area;private String street;
}

正例:

public class User {private UserName username;private Adress adress;
}class UserName{private String firstName;private String lastName;
}
class Address{private String province;private String city;private String area;private String street;
}

9. Primitive Obsession (基本类型偏执)

多数编程环境都有两种数据类型,结构类型和基本类型。这里的基本类型,如果指Java语言的话,不仅仅包括那八大基本类型哈,也包括String等。如果是经常一起出现的基本类型,可以考虑把它们封装成对象。我个人觉得它有点像Data Clumps(数据泥团) 举个反例如下:

// 订单
public class Order {private String customName;private String address;private Integer orderId;private Integer price;
}

正例:

// 订单类
public class Order {private Custom custom;private Integer orderId;private Integer price;
}
// 把custom相关字段封装起来,在Order中引用Custom对象
public class Custom {private String name;private String address;
}

当然,这里不是所有的基本类型,都建议封装成对象,有关联或者一起出现的,才这么建议哈。

10. Switch Statements (Switch 语句)

这里的Switch语句,不仅包括Switch相关的语句,也包括多层if...else的语句哈。很多时候,switch语句的问题就在于重复,如果你为它添加一个新的case语句,就必须找到所有的switch语句并且修改它们。

示例代码如下:

    String medalType = "guest";if ("guest".equals(medalType)) {System.out.println("嘉宾勋章");} else if ("vip".equals(medalType)) {System.out.println("会员勋章");} else if ("guard".equals(medalType)) {System.out.println("守护勋章");}...

这种场景可以考虑使用多态优化:

//勋章接口
public interface IMedalService {void showMedal();
}//守护勋章策略实现类
public class GuardMedalServiceImpl implements IMedalService {@Overridepublic void showMedal() {System.out.println("展示守护勋章");}
}
//嘉宾勋章策略实现类
public class GuestMedalServiceImpl implements IMedalService {@Overridepublic void showMedal() {System.out.println("嘉宾勋章");}
}//勋章服务工厂类
public class MedalServicesFactory {private static final Map<String, IMedalService> map = new HashMap<>();static {map.put("guard", new GuardMedalServiceImpl());map.put("vip", new VipMedalServiceImpl());map.put("guest", new GuestMedalServiceImpl());}public static IMedalService getMedalService(String medalType) {return map.get(medalType);}
}

当然,多态只是优化的一个方案,一个方向。如果只是单一函数有些简单选择示例,并不建议动不动就使用动态,因为显得有点杀鸡使用牛刀了。

11.Parallel Inheritance Hierarchies( 平行继承体系)

平行继承体系 其实算是Shotgun Surgery的特殊情况啦。当你为A类的一个子类Ax,也必须为另一个类B相应的增加一个子类Bx。

解决方法:遇到这种情况,就要消除两个继承体系之间的引用,有一个类是可以去掉继承关系的。

12. Lazy Class (冗赘类)

把这些不再重要的类里面的逻辑,合并到相关类,删掉旧的。一个比较常见的场景就是,假设系统已经有日期工具类DateUtils,有些小伙伴在开发中,需要用到日期转化等,不管三七二十一,又自己实现一个新的日期工具类。

13. Speculative Generality(夸夸其谈未来性)

尽量避免过度设计的代码。例如:

  • 只有一个if else,那就不需要班门弄斧使用多态;

  • 如果某个抽象类没有什么太大的作用,就运用Collapse Hierarchy(折叠继承体系)

  • 如果函数的某些参数没用上,就移除。

14. Temporary Field(令人迷惑的临时字段)

某个实例变量仅为某种特定情况而定而设,这样的代码就让人不易理解,我们称之为 Temporary Field(令人迷惑的临时字段)。反例如下:

public class PhoneAccount {private double excessMinutesCharge;private static final double RATE = 8.0;public double computeBill(int minutesUsed, int includedMinutes) {excessMinutesCharge = 0.0;int excessMinutes = minutesUsed - includedMinutes;if (excessMinutes >= 1) {excessMinutesCharge = excessMinutes * RATE;}return excessMinutesCharge;}public double chargeForExcessMinutes(int minutesUsed, int includedMinutes) {computeBill(minutesUsed, includedMinutes);return excessMinutesCharge;}
}

思考一下,临时字段excessMinutesCharge是否多余呢?

15. Message Chains (过度耦合的消息链)

当你看到用户向一个对象请求另一个对象,然后再向后者请求另一个对象,然后再请求另一个对象...这就是消息链。实际代码中,你看到的可能是一长串getThis()或一长串临时变量。反例如下:

A.getB().getC().getD().getTianLuoBoy().getData();

A想要获取需要的数据时,必须要知道B,又必须知道C,又必须知道D...其实A需要知道得太多啦,回头想下封装性,嘻嘻。其实可以通过拆函数或者移动函数解决,比如由B作为代理,搞个函数直接返回A需要数据。

16. Middle Man (中间人)

对象的基本特征之一就是封装,即对外部世界隐藏其内部细节。封装往往伴随委托,过度运用委托就不好:某个类接口有一半的函数都委托给其他类。可以使用Remove Middle Man优化。反例如下:

A.B.getC(){return C.getC();
}

其实,A可以直接通过C去获取C,而不需要通过B去获取。

17. Inappropriate Intimacy(狎昵关系)

如果两个类过于亲密,过分狎昵,你中有我,我中有你,两个类彼此使用对方的私有的东西,就是一种坏代码味道。我们称之为Inappropriate Intimacy(狎昵关系)

建议尽量把有关联的方法或属性抽离出来,放到公共类,以减少关联。

18. Alternative Classes with Different Interfaces (异曲同工的类)

A类的接口a,和B类的接口b,做的的是相同一件事,或者类似的事情。我们就把A和B叫做异曲同工的类。

可以通过重命名,移动函数,或抽象子类等方式优化

19. Incomplete Library Class (不完美的类库)

大多数对象只要够用就好,如果类库构造得不够好,我们不可能修改其中的类使它完成我们希望完成的工作。可以酱紫:包一层函数或包成新的类

20. Data Class (纯数据类)

什么是Data Class? 它们拥有一些字段,以及用于访问(读写)这些字段的函数。这些类很简单,仅有公共成员变量,或简单操作的函数。

如何优化呢?将相关操作封装进去,减少public成员变量。比如:

  • 如果拥有public字段-> Encapsulate Field

  • 如果这些类内含容器类的字段,应该检查它们是不是得到了恰当地封装-> Encapsulate Collection封装起来

  • 对于不该被其他类修改的字段-> Remove Setting Method->找出取值/设置函数被其他类运用的地点-> Move Method 把这些调用行为搬移到Data Class来。如果无法搬移整个函数,就运用Extract Method产生一个可被搬移的函数->Hide Method把这些取值/设置函数隐藏起来。

21. Refused Bequest (被拒绝的馈赠)

子类应该继承父类的数据和函数。子类继承得到所有函数和数据,却只使用了几个,那就是继承体系设计错误,需要优化。

  • 需要为这个子类新建一个兄弟类->Push Down MethodPush Down Field把所有用不到的函数下推给兄弟类,这样一来,超类就只持有所有子类共享的东西。所有超类都应该是抽象的。

  • 如果子类复用了超类的实现,又不愿意支持超类的接口,可以不以为然。但是不能胡乱修改继承体系->Replace Inheritance with Delegation(用委派替换继承).

22. Comments (过多的注释)

这个点不是说代码不建议写注释哦,而是,建议大家避免用注释解释代码,避免过多的注释。这些都是常见注释的坏味道:

  • 多余的解释

  • 日志式注释

  • 用注释解释变量等

  • ...

如何优化呢?

  • 方法函数、变量的命名要规范、浅显易懂、避免用注释解释代码。

  • 关键、复杂的业务,使用清晰、简明的注释

23. 神奇命名

方法函数、变量、类名、模块等,都需要简单明了,浅显易懂。避免靠自己主观意识瞎起名字。

反例:

boolean test = chenkParamResult(req);

正例:

boolean isParamPass = chenkParamResult(req);

24. 神奇魔法数

日常开发中,经常会遇到这种代码:

if(userType==1){//doSth1
}else If( userType ==2){//doSth2
}
...

代码中的这个1和2都表示什么意思呢?再比如setStatus(1)中的1又表示什么意思呢?看到类似坏代码,可以这两种方式优化:

  • 新建个常量类,把一些常量放进去,统一管理,并且写好注释;

  • 建一个枚举类,把相关的魔法数字放到一起管理。

25. 混乱的代码层次调用

我们代码一般会分dao层service层controller层

  • dao层主要做数据持久层的工作,与数据库打交道。

  • service层主要负责业务逻辑处理。

  • controller层负责具体的业务模块流程的控制。

所以一般就是controller调用serviceservicedao。如果你在代码看到controller直接调用dao,那可以考虑是否优化啦。反例如下

@RestController("user")
public class UserController {Autowiredprivate UserDao userDao;@RequestMapping("/queryUserInfo")public String queryUserInfo(String userName) {return userDao.selectByUserName(userName);}
}

参考与感谢

  • 软工实验:常见的代码坏味道以及重构举例[2]

  • 22种代码的坏味道,一句话概括[3]

  • 【重构】 代码的坏味道总结 Bad Smell[4]

  • Code Smell[5]

  • 《重构改善既有代码的设计》


往期推荐

ThreadLocal内存溢出代码演示和原因分析!


SimpleDateFormat线程不安全的5种解决方案!


2万字!66道并发面试题及答案



本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/544771.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

滚动照片抽奖软件

CODE GitHub 源码 1、女友说很丑的一个软件 说个最近的事情&#xff0c;女友公司过年了要搞活动&#xff0c;需要个抽奖的环节&#xff0c;当时就问我能不能给做一个&#xff0c;正好我也没啥事儿&#xff0c;就在周末的时候用C#做了一个&#xff0c;虽然派上用场了&#xf…

Java即时类| 带示例的compareTo()方法

即时类compareTo()方法 (Instant Class compareTo() method) compareTo() method is available in java.time package. compareTo()方法在java.time包中可用。 compareTo() method is used to compare this Instant object to the given object. compareTo()方法用于将此Instan…

11个小技巧,玩转Spring!

前言最近有些读者私信我说希望后面多分享spring方面的文章&#xff0c;这样能够在实际工作中派上用场。正好我对spring源码有过一定的研究&#xff0c;并结合我这几年实际的工作经验&#xff0c;把spring中我认为不错的知识点总结一下&#xff0c;希望对您有所帮助。一 如何获取…

MFC中的几种播放声音的方法

一&#xff0e;播放声音文件的简单方法  在VC 中的多媒体动态连接库中提供了一组与音频设备有关的函数。利用这些函数可以方便地播放声音。最简单的播放声音方法就是直接调用VC中提供的声音播放函 数BOOL sndPlaySound ( LPCSTR lpszSound,UINT fuSound ); 或BOOL PlaySound(…

标志枚举的使用

标志枚举的使用大多是在标记多重状态&#xff0c;比如说文件的属性&#xff1a;只读&#xff0c;可写&#xff0c;隐藏&#xff0c;系统文件等相关属性&#xff0c;都对应相应的标志位&#xff0c;如果在C#中想实现自己的标志枚举&#xff0c;也是可以的&#xff0c;下文是亲身…

duration java_Java Duration类| 带示例的getUnits()方法

duration java持续时间类getUnits()方法 (Duration Class getUnits() method) getUnits() method is available in java.time package. getUnits()方法在java.time包中可用。 getUnits() method is used to get the List object that contains the units of seconds and Nanos …

synchronized 的超多干货!

synchronized 这个关键字的重要性不言而喻&#xff0c;几乎可以说是并发、多线程必须会问到的关键字了。synchronized 会涉及到锁、升级降级操作、锁的撤销、对象头等。所以理解 synchronized 非常重要&#xff0c;本篇文章就带你从 synchronized 的基本用法、再到 synchronize…

团队项目—第二阶段第三天

昨天&#xff1a;快捷键的设置已经实现了 今天&#xff1a;协助成员实现特色功能之一 问题&#xff1a;技术上遇到了困难&#xff0c;特色功能一直没太大的进展。网上相关资料不是那么多&#xff0c;我们无从下手。 有图有真相&#xff1a; 转载于:https://www.cnblogs.com/JJJ…

C# struct 装箱拆箱例子

值类型&#xff1a;拆箱、装箱 struct是值类型 struct和class的区别 类是引用类型&#xff0c;struct是值类型在托管堆上创建类的实例&#xff0c;在栈上创建struct实例类实例的赋值&#xff0c;赋的是引用地址&#xff0c;struct实例的赋值&#xff0c;赋的是值类作为参数类…

stl min函数_std :: min_element()函数以及C ++ STL中的示例

stl min函数C STL std :: min_element()函数 (C STL std::min_element() function) min_element() function is a library function of algorithm header, it is used to find the smallest element from the range, it accepts a container range [start, end] and returns a…

不重启JVM,替换掉已经加载的类,偷天换日?

来源 | 美团技术博客在遥远的希艾斯星球爪哇国塞沃城中&#xff0c;两名年轻的程序员正在为一件事情苦恼&#xff0c;程序出问题了&#xff0c;一时看不出问题出在哪里&#xff0c;于是有了以下对话&#xff1a;“Debug一下吧。”“线上机器&#xff0c;没开Debug端口。”“看日…

[nodejs] 利用openshift 撰寫應用喔

2019独角兽企业重金招聘Python工程师标准>>> 朋友某一天告訴我,可以利用openshift來架站,因為他架了幾個nodejs應用放在上面,我也來利用這個平台架看看,似乎因為英文不太行,搞很久啊!! 先來架一個看看,不過架好之後,可以有三個應用,每個應用有1G的空間,用完就沒啦~~…

C#单例模式的简单使用

单例模式示例&#xff1a; public sealed class WindowService {//定义一个私有的静态全局变量来保存该类的唯一实例private static WindowService Service;//定义一个只读静态对象//且这个对象是在程序运行时创建的private static readonly object syncObject new object();…

stl max函数_std :: max_element()函数以及C ++ STL中的示例

stl max函数C STL std :: max_element()函数 (C STL std::max_element() function) max_element() function is a library function of algorithm header, it is used to find the largest element from the range, it accepts a container range [start, end] and returns an…

详解4种经典的限流算法

最近&#xff0c;我们的业务系统引入了Guava的RateLimiter限流组件&#xff0c;它是基于令牌桶算法实现的,而令牌桶是非常经典的限流算法。本文将跟大家一起学习几种经典的限流算法。限流是什么?维基百科的概念如下&#xff1a;In computer networks, rate limiting is used t…

css clearfix_如何使用CSS清除浮点数(clearfix)?

css clearfixIntroduction: 介绍&#xff1a; Dealing with various elements on a website or web page can sometimes prove to create many problems hence one should be aware of many properties, tricks or ways to cope with those problems. We do not want our webs…

C# 写入注册表启动项

C# 写入注册表启动项 private void RegisterSelfKey() {try{string strName Application.ExecutablePath;if (!File.Exists(strName))return;string strnewName strName.Substring(strName.LastIndexOf("\\") 1);RegistryKey RKey Registry.LocalMachine.OpenSu…

将你的Windows,快速打造成Docker工作站!

手里的macbook因为键盘问题返厂维修了&#xff0c;只好抱起了久违的Windows。首先面临的&#xff0c;就是Docker问题。docker好用&#xff0c;但安装麻烦&#xff0c;用起来也命令繁多。一个小白&#xff0c;如何打造舒适的docker环境&#xff0c;是一个非常有挑战的问题。本文…

HTML5游戏引擎Egret发布2.0版 开发工具亦获更新

5月22日在北京国际会议中心举办的HTML5游戏生态大会上&#xff0c;白鹭时代旗下游戏引擎Egret Engine发布2.0版&#xff0c;同时还发布了Flash转换HTML5工具Egret Conversion、HTML5游戏加速Egret Runtime 2.0、GUI可视化编辑器Egret Wing 2.0、骨骼动画工具DragonBones4.0、富…

DES和AES加密:指定键的大小对于此算法无效

“System.ArgumentException”类型的未经处理的异常在 mscorlib.dll 中发生 其他信息: 指定键的大小对于此算法无效。 在看DES和AES加密的时候&#xff0c;找了个加密的Demo&#xff0c;自己试验的时候总是报&#xff1a;指定键的大小对于此算法无效 的错误。 原因为&#xf…