• C#程序中注释过多的8条理由


    C#程序中注释过多的8条理由

    程序中中的注释,一般是有益处的,可以知晓程序的一些逻辑说明,或是参数解释。但是有些程序,因为注释太多,反而引起维护上的不方便,删掉了怕以后不能出现问题不好查找原因,不删除留在代码中,对程序的维护人员,是一种痛苦。

    以下列举我可以理解的的原因,供分析参考。

    1  方法调用移动到新的类型中,原方法仍然保留在原来的类型中

    //public void ExecuteSqlCommand(string sqlCommandText)
    //{
           //this.ExecuteSqlCommand(sqlCommandText, CommandType.Text, null);
    //}
    ......
     

    ExecuteSqlCommand方法已经被移植到新的辅助类型SqlHelper中,但是这里的还没有直接删除。保留的目的,有可能存在反射调用,在报错之后,看到这里的代码被注释后,再才会重新查找这片代码的新的归属。

    2  删除不需要考虑的的条件或情况,因为怕考虑不充分而没有删除代码

     static ClientProxyFactory()
            {
                _managerTypeAssemblies = new List<string>();
                _managerTypesCache = new Dictionary<string, Type>();
                _managerInstancesCache = new Dictionary<string, IManagerBase>();
                EnableManagerInstanceCache = true;
    
                //if (Platform == CommunicationPlatform.Local)
                //{
                //    foreach (string file in ManagerAssembly)
                //    {
                //        if (File.Exists(String.Format("{0}.dll", file)))
                //        {
                //            Assembly assembly = Assembly.Load(file);
                //                _managerTypeAssemblies.Add(assembly);
                //        }
                //    }
                //}
            }
    ......

    在上面的代码中,CommunicationPlatform为Local的情况被注释掉了,但是没有直接删除。被注释的代码的作用是添加程序集到_managerTypeAssemblies类型中。可能是的原因是,系统现在不再支持Local模式,而只支持.net Remoting模式,所以这段代码会被注释。

    3  因为考虑不周全,导致代码中注释与功能并存。保留注释是为了出错的情况下,帮助分析代码

    来看下面的二个公共方法的定义,一个是反射调用静态方法,另一个是反射调用静态属性的值。

     /// <summary>
    /// 静态方法的调用
    /// </summary>
    /// <param name="file"></param>
    /// <param name="typeName"></param>
    /// <param name="methodName"></param>
    /// <returns></returns>
    public static object InvokeStaticMethod(Type typeName,string methodName,object [] args)
            {
                //Assembly  assembly = Assembly.LoadFile(file);
                //Type type = assembly.GetType(typeName);
                Assembly assembly = typeName.Assembly;
    
                //obj2 = Activator.CreateInstance(type, args);
    
                System.Reflection.MethodInfo method = typeName.GetMethod(methodName,new Type[]{ typeof(object)});
               // object obj= assembly.CreateInstance(typeName);
    
               // object obj = Activator.CreateInstance(typeName, args);
                return typeName.InvokeMember(methodName, BindingFlags.Public | BindingFlags.Static, null, null, args);
            }
    
            public static object GetStaticPropertyValue(Type type, string propertyName)
            {
                object objec=CreateObjectInstance(type);
                PropertyInfo propertyInfo = type.GetProperty(propertyName,BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly);
                //type.GetProperty(propertyName).GetValue(null, null);
                return propertyInfo.GetValue(objec, null);
            }

    从上面被注释的代码中可以看到,需要的代码与被注释的代码共同存在。可能因为参数或是条件的不同,被注释的代码可以运行,是正确的,但是当前情况下,没有被注释的代码才可以运行。公共框架的开发本身要考虑的条件很多,测试也要充分才能保证无错。从这里也可以看出,反射给代码重构带来障碍,因为不知道代码在哪里会被反射调用,所以代码只有等到运行出错之后才发现。

    除非正常调用情况下无法实现,应该减少反射调用代码。或者对反射调用代码进行封装,所有的反射调用放在一个ReflectionHelper类型中,如果要查找问题,只需要在这个类型的相应方法中打断点即可。

    4  异常处理机制的改变,导致代码中捕获异常的代码被注释

    请看下面的二个方法,用于拷贝文件和拷贝目录

    //bakup file 
    public static BackupFile(string sourceFileName, string destFileName)
    {
              try
               {
                    System.IO.File.Copy(sourceFileName, destFileName, true);
                    return true;
                }
                catch (Exception e)
                {
                    throw e;
                }
    }
    
    public static void CopyDirectory(string oldDir, string newDir)
            {
                try
                {
                    DirectoryInfo dInfo = new DirectoryInfo(oldDir);
                    CopyDirInfo(dInfo, oldDir, newDir);
                }
                catch (Exception exc)
                {
                    throw new Exception(exc.ToString());
                }
            }

    这种依靠返回true/false的得知代码是否执行成功。我现在比较反感这样的代码。因为如果拷贝文件或拷贝目录出错,没有报错,异常在这里被捕获。而且第二个方法CopyDirectory中,抛出异常后会改变异常的堆栈信息,这样导致比较难发现错误。如果是WinForms程序,应该以下面的方式处理异常

     CustomExceptionHandler eh = new CustomExceptionHandler();
                AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CustomExceptionHandler.CurrentDomain_UnhandledException);
                Application.ThreadException += new ThreadExceptionEventHandler(eh.OnThreadException);
           

    在程序的入口处,设置UnhandledException 和ThreadException 的处理情况,程序中有发生异常后,流程会跳转到这里,作统一的处理。以我的实践,像下面这样的方法,不应该这样处理

    /// <summary>
            /// 复制文件,如果目标文件已经存在则覆盖掉
            /// </summary>
            /// <param name="oldFile">源文件</param>
            /// <param name="newFile">目标文件</param>
            public static void CopyFile(string oldFile, string newFile)
            {
                try
                {
                    File.Copy(oldFile, newFile, true);
                }
                catch (Exception exc)
                {
                    throw new Exception(exc.ToString());
                }
            }

    而修改的异常捕获策略之后,代码像这样,也不友好

    /// <summary>
            /// 复制文件,如果目标文件已经存在则覆盖掉
            /// </summary>
            /// <param name="oldFile">源文件</param>
            /// <param name="newFile">目标文件</param>
            public static void CopyFile(string oldFile, string newFile)
            {
                //try
                //{
                    File.Copy(oldFile, newFile, true);
                //}
               // catch (Exception exc)
                //{
                //    throw new Exception(exc.ToString());
                //}
            }

    应该直接去掉这个方法封装,直接在代码中调用File.Copy。

    5  .NET框架的发展,导致一些代码变成多余但又没有删掉,先将其注释

    动态构造SELECT语句的字段列时,在构造完成后,通常会给它们加上逗号

    SELECT  ITEM_NO ,ITEM_GROUP FROM GBITEM
     

    通常我们会用ArrayList或是IList<string> 把ITEM_NO和ITEM_GROUP聚集在一起,再循环一次,给每个字符的末尾增加一个逗号,最后去掉多余的逗号:

     public static string ArrayToList(string[] ids, string separativeSign)
        {
            int num = 0;
            string str = string.Empty;
            foreach (string str2 in ids)
            {
                num++;
                string str3 = str;
                str = str3 + separativeSign + str2 + separativeSign + ",";
            }
            if (num == 0)
            {
                return "";
            }
            return str.TrimEnd(new char[] { ',' });
        }

    MSDN中字符串类型string的Join方法,可以达到这个目的,只需要调用Join方法即可。MSDN中有例子解释如下

    如果 separator 为“,”且 value 的元素为“apple”、“orange”、“grape”和“pear”,则 Join(separator, value) 返回“apple, orange, grape, pear”。 如果 separator 为 nullNothingnullptrnull 引用(在 Visual Basic 中为 Nothing),则改用空字符串 (Empty)。

     
     

    6 运行环境的改变,注释掉代码以便于以后发现问题

    请参考下面的方法例子

     /// <summary>
            /// 获取一个文件的绝对路径(适用于WEB应用程序)
            /// </summary>
            /// <param name="filePath">文件路径</param>
            /// <returns>string</returns>
            public static string GetRealFile(string filePath)
            {
                string strResult = "";
    
                //strResult = ((file.IndexOf(@":") > 0 || file.IndexOf(":/") > 0) ? file : System.Web.HttpContext.Current.Server.MapPath(System.Web.HttpContext.Current.Request.ApplicationPath + "/" + file));
                strResult = ((filePath.IndexOf(":\") > 0) ?
                    filePath :
                    System.Web.HttpContext.Current.Server.MapPath(filePath));
    
                return strResult;
            }

    这个方法之前可能是用Web环境中,现在改成WinForms或是控制台项目中,导致被注释的代码会报错,于是将它注释。关于路径的选择,AppDomain的BaseDirectory或是Application.ExecutePath都是独立于运行环境的(ASP.NET,Console,WinForms,Windows Services),应该优先考虑使用。

    7  测试数据以注释的方式,保留中代码中,增加对代码的解释

     string host = System.Configuration.ConfigurationManager.AppSettings["EmailHost"];
     MailMessage m = new MailMessage();
    m.Subject = subject;
    m.SubjectEncoding = Encoding.UTF8;
    m.From = new MailAddress(from);
    m.To.Add(to);
    m.Body = body;
    m.BodyEncoding = Encoding.UTF8;
    m.IsBodyHtml = true;
    SmtpClient client = new SmtpClient();
    client.Host = host; //"ASHKGEX4.asia.ad.flextronics.com";
    client.Credentials = new System.Net.NetworkCredential("asiaaoshhli", "");
    client.Port = 25;
    client.DeliveryMethod = SmtpDeliveryMethod.Network;
    client.UseDefaultCredentials = false;
    client.Send(m);
     

    如上面代码中的host=ASHKGEX4.asia.ad.flextronics.com,作者测试问题时是用这个host也没有报错,于是将这个数据保留在代码中,以方便以后代码维护人员测试问题。

    8  对每一个数据项都进行注释,必要的注释和不必要的注释混杂在一起

    例如下面的代码

    DataTable Dt = new DataTable();
    DataRow Dr;
    
    Dt.Columns.Add("name");//名称
    Dt.Columns.Add("type");//类型:1为文件夹,2为文件
    Dt.Columns.Add("size");//文件大小,如果是文件夹则置空
    Dt.Columns.Add("content_type");//文件MIME类型,如果是文件夹则置空
    Dt.Columns.Add("createTime");//创建时间
    Dt.Columns.Add("lastWriteTime");//最后修改时间

    Add方法后面的对字段的解释,有的是是多余的。有的是必要的。

    我以为,多余的注释是:名称,创建时间 ,最后修改时间  这三列的值可以通过代码或是它本身的名字得知。

    type这一列的注释,我以为这是很有必要的,这可以减少维护人员的工作量。

     
     
  • 相关阅读:
    语音激活检测(VAD)--前向神经网络方法(Alex)
    语音信号处理基础
    MySQL死锁系列-插入语句正常,但是没有插入成功
    关于wx.getProfile和wx.login获取解密数据偶发失败的原因
    指针访问数组元素
    libev 源码解析
    leveldb 源码--总体架构分析
    raft--分布式一致性协议
    使用springcloud gateway搭建网关(分流,限流,熔断)
    爬虫
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3143187.html
Copyright © 2020-2023  润新知