代码走查25条疑问 C# 跳转新的标签页 C#线程处理 .Net 特性 attribute 学习 ----自定义特性 看懂 ,学会 .NET 事件的正确姿势-简单版

时间:2022-09-07 14:56:16

代码走查25条疑问

代码走查(Code Review) 是一个开发人员与架构师集中讨论代码的过程。通过代码走查可以提高代码的

质量,同时减少Bug出现的几率。但是在小公司中并没有代码走查的过程在这里总结和记录一些代码走

查的要求,时刻提醒自己注重代码质量,每天下班前自己走查一下自己的代码。代码走查一些注意事项

如下:

  1. 代码的注释与代码是否一致?注释是否是多余的?
  2. 是否存在超过3层嵌套的循环与/或判断?
  3. 变量的命名是否代表了其作用?
  4. 所有的循环边界是否正确?
  5. 所有的判断条件边界是否正确?
  6. 输入参数的异常是否处理了?
  7. 程序中所有的异常是否处理了?
  8. 是否存在重复的代码?
  9. 是否存在超过25行的方法?
  10. 是否存在超过7个方法的类?
  11. 方法的参数是否超过3个?
  12. 是否有多种原因导致修改某个类?
  13. 当发生某个功能变化时,是否需要修改多个类?
  14. 代码中的常量是否合适?
  15. 一个方法是否访问了其他类的多个属性?
  16. 某几项数据是否总是同时出现,而又不是一个类的属性?
  17. switch语句是否可以用类来替代?
  18. 是否有一类的职责很少?
  19. 是否有一个类的某些属性或者方法没有被其他类所使用?

  20. 在类的方法中是否存在如下的调用形式:a.b().c()?

  21. 是否某个类的方法总是调用另外一个类的同名方法?

  22. 是否某个类总是访问另外一个类的属性与方法?

  23. 是否两个类完成了类似的工作,使用了不同的方法名,却没有拥有同一个父类?

  24. 是否某个类仅有字段和简单的赋值方法与取值方法构成?

  25. 是否某个子类仅使用了父类的部分属性或方法?

这25条疑问就是代码规范的修炼手册,这25条疑问是别人总结出来的,记录在此用于提醒自己,

原文出处:https://blog.csdn.net/zzh920625/article/details/51475191

C# 跳转新的标签页

///这个是拿别人的,找到好多这个方法,溜了,不知道谁是原创

protected void btnPrint_Click(object sender, EventArgs e)
        {
            string url = "QR_CodePrintView.aspx?Code=" + tbAssetCode.Text + ";";
            Redirect(Response, url, "_blank", "'toolbar=0,scrollbars=1,status=0,menubar=0,resizable=1,top=0,left=0,height=800,width=1000");
        }
        /// <summary>
        /// 打开新的标签页
        /// </summary>
        /// <param name="response"></param>
        /// <param name="url"></param>
        /// <param name="target"></param>
        /// <param name="windowFeatures"></param>
        private void Redirect(HttpResponse response, string url, string target, string windowFeatures)
        {
            if ((String.IsNullOrEmpty(target) || target.Equals("_self", StringComparison.OrdinalIgnoreCase)) && String.IsNullOrEmpty(windowFeatures))
            {
                response.Redirect(url);
            }
            else
            {
                Page page = (Page)HttpContext.Current.Handler;
                if (page == null)
                {
                    throw new
                    InvalidOperationException("Cannot redirect to new window .");
                }
                url = page.ResolveClientUrl(url);
                string script;
                if (!String.IsNullOrEmpty(windowFeatures))
                {
                    script = @"window.open(""{0}"", ""{1}"", ""{2}"");";
                }
                else
                {
                    script = @"window.open(""{0}"", ""{1}"");";
                }
                script = String.Format(script, url, target, windowFeatures);
                ScriptManager.RegisterStartupScript(page, typeof(Page), "Redirect", script, true);
            }
        }

C#线程处理

  C#支持通过多线程并行地执行代码,一个线程有它独立的执行路径,能够与其它的线程同时地运行。一个C#程序开始于一个单线程,这个单线程是被CLR和操作系统(也称为“主线程”)自动创建的,并具有多线程创建额外的线程。
  除非被指定,否则所有的例子都假定以下命名空间被引用了:

using System;
using System.Threading;

C#开启线程的方法有:

  • 异步委托
  • 通过Thread类
  • 线程池
  • 任务

  总的来说其实线程的开启基本都涉及到委托的使用。

一、异步委托开启线程

首先来看一个比较简单的例子,采用第一种开启线程的方法——异步委托

using System;
using System.Threading;

namespace Study
{
    class Program
    {
        static void test()
        {
            Console.WriteLine("TestThread");
        }
        static void Main(string[] args)
        {
            Action a = test;
            a.BeginInvoke(null, null);
            Console.WriteLine("MainThread");
            Console.ReadLine();
        }
    }
}

  编译运行,发现结果与预期有所不同。结果如下图
代码走查25条疑问  C# 跳转新的标签页  C#线程处理  .Net 特性 attribute 学习 ----自定义特性  看懂 ,学会 .NET 事件的正确姿势-简单版
  如果按着逐行运行代码的方式,那么应该是先输出TestThread,但是结果却是先输出MainThread。
  将a.BeginInvoke(null,null);Console.WriteLine("MainThread");对调位置之后,结果和之前的依然一致。这就说明,异步委托开启的线程是和主线程同时同步进行的。
  Action委托是指向一个没有返回值的函数,那么假设一个线程,我们需要取得他的返回结果并输出,那么就要用到Func委托。
  看下面的源码

using System;
using System.Threading;

namespace SummerStudy
{
    class Program
    {
        static string test(int i, string str)
        {
            Console.WriteLine("TestThread" + "\t参数i是:" + i);
            return str;
        }
        static void Main(string[] args)
        {
            Func<int, string, string> a = test;
            IAsyncResult res = a.BeginInvoke(1, "返回值", null, null);
            string o = a.EndInvoke(res);
            Console.WriteLine("MainThread\t" + "线程返回值是:" + o);
            Console.ReadLine();
        }
}

代码走查25条疑问  C# 跳转新的标签页  C#线程处理  .Net 特性 attribute 学习 ----自定义特性  看懂 ,学会 .NET 事件的正确姿势-简单版
同时异步委托开启线程中,判断线程是否结束的方法也有两种,一种是利用IAsyncResult的IsCompleted方法,一种是使用方法进行线程结束判断。
  具体使用方法如下。

  1. IsCompleted(bool)
IAsyncResult ia = a.BeginInvoke()
if(ia.IsCompleted == false)
{
    //GoOn
}
  1. AsyncWaitHandle
IAsyncResult ia = a.BeginInvoke()
ia.AsyncWaitHandle.WaitOne(Time);//Time为等待时间,超时后才会运行下一行代码,未完成直接跳出返回false

  或者通过自定义方法,BeginInvoke中倒数第二个参数是一个委托,传递一个函数,在线程结束之后会自动的调用。

static string Test(int a)
{

}
Func<int, string> a = Test;
IAsyncResult ia = a.BeginInvoke(100, CallBack, a);
static void CallBack(IAsyncResult ar)
{
    Func<int, string> a = ia.AsyncState as Func<int, string>;
    string res = a.EndInvoke(ar);
}

  在使用Lambda表达式作为委托的时候,最后一个参数可以为空,因为Lambda表达式可以访问外部变量。

二、使用Thread类开启线程

  使用Thread类创建一个实例,它的构造方法中需要传递一个委托。通过委托绑定线程。
  直接上代码

using System;
using System.Threading;

namespace Study
{
    class Program
    {
        static void test()
        {
            Console.WriteLine("Thread");
            Thread.Sleep(2000);
            Console.WriteLine("TimeOver");
        }
        static void Main(string[] args)
        {
            Thread t = new Thread(test);
            t.Start();
            Console.WriteLine("Main");
            Console.Read();
        }
    }
}

代码走查25条疑问  C# 跳转新的标签页  C#线程处理  .Net 特性 attribute 学习 ----自定义特性  看懂 ,学会 .NET 事件的正确姿势-简单版
  对于需要传递参数的委托,则必须制定参数类型为object,在线程Start方法中传递参数

namespace SummerStudy
{
    class Program
    {
        static void test(object c)
        {
            int id = Thread.CurrentThread.ManagedThreadId;
            Console.WriteLine("Thread,\t线程id为" + id + ",\t参数是:" + c);
            Thread.Sleep(2000);
            Console.WriteLine("TimeOver");

        }
        static void Main(string[] args)
        {
            Thread t = new Thread(test);
            t.Start("xxx.avi");
            Console.WriteLine("Main");
            Console.Read();
        }
    }
}

代码走查25条疑问  C# 跳转新的标签页  C#线程处理  .Net 特性 attribute 学习 ----自定义特性  看懂 ,学会 .NET 事件的正确姿势-简单版
  当然你也可以自定义一个类,在类中自定义数据传递。

三、线程池

  这种方法有助于节省时间,具体使用方法如下

using System;
using System.Threading;

namespace SummerStudy
{
    class Program
    {
        static void test(object c)
        {
            int id = Thread.CurrentThread.ManagedThreadId;
            Console.WriteLine("Thread,\t线程id为" + id + ",\t参数是:" + c);
            Thread.Sleep(2000);
            Console.WriteLine("TimeOver");

        }
        static void Main(string[] args)
        {
            ThreadPool.QueueUserWorkItem(test, "asfasf");
            Console.Read();
        }
    }
}

  其中委托必须要有一个参数,无论是否使用该参数。且只适用于使用时间短的线程,不能改变优先级

四、任务

  使用Task类开启线程,还有TaskFactory创建
  Task类实例

using System;
using System.Threading;
using System.Threading.Tasks;

namespace SummerStudy
{
    class Program
    {
        static void test(object c)
        {
            int id = Thread.CurrentThread.ManagedThreadId;
            Console.WriteLine("Thread,\t线程id为" + id);
            Thread.Sleep(2000);
            Console.WriteLine("TimeOver");

        }
        static void Main(string[] args)
        {
            Task t = new Task(test, "Asfgasg");
            t.Start();

            //或者

            TaskFactory tf = new TaskFactory();

            Task t1 = tf.StartNew(test);
            Console.Read();
        }
    }
}

.Net 特性 attribute 学习 ----自定义特性

什么是特性?
[Obsolete("不要用无参构造函数",true)] 放在方式上, 该方法就不能使用了
 [Serializable]放在类上面。该类就是可以序列化和反序列化使用了。
在命名空间、类、方法、属性、字段、枚举 上用中括号[]
自定义特性,特性就是类:必须继承Attribute 或者是Attribute的泛生类
public class SizeAttribute : Attribute       // 这个就是一个自定义特性
{
          public SizeAttribute()
          {
                   Console.WriteLine("这是一个SizeAttribute的构造函数");
           }
这个特性就创建好了
在其他类, 如Student类上
[SizeAttribute]        //在类上写特性
public class Student
{
         [SizeAttribute] //在属性上写特性
          public int Id{set; get;}
          public string Name{set;get}
           [SizeAttribute] //在方法上写特性
           public void Show()
           {
                   Console.WriteLine("Show")
             }
}
当然特性 也可以有描述自己特性的办法
就是在特性上面写上
[AttributeUsage(AttributeTargets.All,AllowMultiple =false,Inherited =true)]
public class SizeAttribute : Attribute
{
}
//意思是当前特性包含所有类型都可以使用,只能单一使用,可以继承
特性:
1.当程序编译和执行,特性和注释的效果是一样的,没有任何不同
2.特性编译后是metadata,只有在反射的时候,才能使用特性。
3.特性可以做权限检测,属性验证,封装枚举等很多功能。
4.特性是一个类,可以用作标记元素,编译时生成在metadata里,平时不影响程序的运行,除非主动用反射去查找,
可以得到一些额外的信息和操作,提供了更丰富扩展空间,特性可以在不 破坏类型封装的前提下,额外增加功能。
例子:有一个学生类,希望用特性,让添加的学生年龄不能小于12岁,大于20岁
//学生类
public class Student
{
            public int Id { get; set; }

public string Name { get; set; }

public int Age { get; set; }

[Obsolete("不要用无参构造函数",true)] //这个特性,是不能使用无参构造函数
            public Student()
            { }

public Student(int id, string name,int age)
           {
            this.Id = id;
            this.Name = name;

            [ControlAgeAttribute(_vMin=12,_vMax=30)] //要判断年龄,年龄小于20,大于12, 就将下面自定义的特性放在这个属性上面
            this.Age = age;
            }

public void Show()
            {
              Console.WriteLine("这个show方法");
             }
}

//控制年龄的特性 :特性的命名规范--名称后面为Attribute
public class ControlAgeAttribute : Attribute
{
          public int _vMin{get;set;}//最小年龄 
           public int _vMax{get;set;} //最大年龄        
          public bool  CompareAge(int age)
          {
                   return age>_vMin && age <_vMax ? true : false; //
           }
}
//反射使用特性---用静态方法
public static class Manage
{
          public static bool CompareAgeManage(this Student stu)
         {
               bool result = false;
               Type type = typeof(stu);//先获取类型
                ProperyInfo prop = type.GetProperty("Age");//反射获取年龄属性
                if (prop.IsDefined(typeof(ControlAgeAttribute ),true))//判断当前属性是否有ControlAgeAttribute 的特性
                {
                      ControlAgeAttribute  attribute = (ControlAgeAttribute) prop.GetCustomAttribute(typeof(ControlAgeAttribute ),true);
                        //获取特性
                      result =  attribute.CompareAge(stu.Age);
                      return result;//得到结果返回
                 }
                 
                        
              return result;
         }
}
//控制台Main方法里面执行
static void Main(string[] args)
{
Student student = new Student(12,"hahaha",15);
Console.WriteLine(student.CompareAgeManage());  //15在12和20 之间,所以是True;

}



看懂 ,学会 .NET 事件的正确姿势-简单版

发现之前写了一篇关于事件的阐述写的过于抽象。现在想想先理解本质由简入难比较合适
  之前的一篇博客地址:https://www.cnblogs.com/LiMin/p/7212217.html

参照网上例子给个简单版本的如下:猫叫->老鼠跑了->主人醒了

代码走查25条疑问  C# 跳转新的标签页  C#线程处理  .Net 特性 attribute 学习 ----自定义特性  看懂 ,学会 .NET 事件的正确姿势-简单版
using System;

namespace EventTest
{
    public class EventDemo
    {
        public void EventTest()
        {
            Cat cat = new Cat();
            Mouse ms = new Mouse();
            Master mas = new Master();
            cat.Calling += ms.Escape;//老鼠对 clling 订阅
            cat.Calling += mas.Wakened;//人 对 calling 订阅
            cat.Call(); //猫叫
        }
    }
    public sealed class Cat
    {
        public event EventHandler Calling;
        public void Call()
        {
            Console.WriteLine("猫叫了...");
            Calling?.Invoke(this, EventArgs.Empty);
        }
    }
    public sealed class Mouse : EventArgs
    {
        public void Escape(object sender, EventArgs e)
        {
            Console.WriteLine("老鼠逃跑了...");
        }
    }
    public sealed class Master
    {
        public void Wakened(object sender, EventArgs e)
        {
            Console.WriteLine("主人醒了");
        }
    }
}
代码走查25条疑问  C# 跳转新的标签页  C#线程处理  .Net 特性 attribute 学习 ----自定义特性  看懂 ,学会 .NET 事件的正确姿势-简单版