架构师的入门基础

前言

反射

编制程序其实正是写代码,而写代码目标正是落实工作,所以,语法和框架也是为了促成业务而留存的。因而,不管多么巨大上的对象,实质上都以业务。

简介

  反射是
.NET中的首要体制,通过反射,能够在运行时收获程序或程序聚焦类型(包蕴class、struct、delegate、interface 和 enum 等)的积极分子和成员的新闻。

  通过反射,就可以对每一样档期的顺序胸有定见,何况也足以透过反射成立、调用和访问对象,纵然在编写翻译时不分明该对象的种类。

  程序集带有模块,模块包含类型,而项目包涵成员。反射提供包装程序集、模块和档期的顺序的靶子。能够选择反射动态地创设项指标实例,将项目绑定到存活对象,或从现成对象中得到项目。

故此,笔者以为并非把写代码上涨到正确的低度。上涨到方式就足以了,因为艺术本人也并未有中度。。。。

优缺点

  优点:

  1. 增加了前后相继的灵活性和扩大性;
  2. 跌落耦合性;
  3. 它同意程序制造和调节别的类的目的,没有供给提前硬编码指标类。

  缺点:

  1. 属性:使用反射基本上是一种解释操作,从理论上讲使用反射远慢于直接代码;
  2. 可读性裁减。

软件设计存在过度设计,语法和框架的知道,也设有过度明白。举例,反编写翻译下,看看反射是怎么落实的。。。

反射的门类成员消息

  • Assembly:定义和加载程序集。

  • Module:模块音讯(如带有模块的程序集和模块中的类)。

  • ConstructorInfo:构造函数音信(如名称、参数、访谈修饰符等)。
  • MethodInfo:方法成员消息(如名称、再次回到类型、参数和做客修饰符等)。

  • FieldInfo:字段成员音讯(如名称、访谈修饰符)。

  • 伊夫ntInfo:事件成员消息(如名称、事件管理程序的数据类型、自定义天性、注解类型以及事件的反射的花色)。

  • PropertyInfo:属性成员音讯(如名称、数据类型、注解类型,反射的类型和性情的只读或可写状态),并赢得或安装属性值。

  • ParameterInfo:参数成员音讯(如参数名、数据类型以及参数在章程具名中的地方等)。

  • CustomAttributeData:自定义天性音讯。

  System.Reflection.Emit命名空间的类提供一种专用方式的反光,使您可见在运行时生成类型。

有乐趣是好事,但纵然知道了反光的本来面目,了然了反光是何等设计的,你技能也没怎么质的改变。因为,技艺水平最终依然要兑现到利用上。

反射的简便用法

  命名空间:System.Reflection、System.Type、System.Reflection.Assembly

  常见的获得 Type 对象的用法:

            Type type1 = typeof(string);            string msg = "";            Type type2 = msg.GetType();

在诸如,过度的求偶代码质量,也未见得是一件善事,因为,[大多数]事态下,硬件比程序员实惠多了。。。(注意这里指的是代码不是算法和数据库品质)

一个大范围的演示用法

  我们一初阶学习三层架构的时候,都应有会融洽跟着导师动手塑造叁个SqlHelper
的吧,这里自身截取贰个因此反射读取数据库数据并填充到三个指标的属性上,通过轮回遍历,最终生成多个list 列表的代码。

        /// <summary>        /// 执行 Reader 并读取数据转换成集合        /// </summary>        /// <typeparam name="T"></typeparam>        /// <param name="sql"></param>        /// <param name="commandType"></param>        /// <param name="parameters"></param>        /// <returns></returns>        public static IList<T> ExecuteReaderToList<T>(string sql, CommandType commandType = CommandType.Text,            params SqlParameter[] parameters) where T : new()        {            var type = typeof;            var props = type.GetProperties();            var list = new List<T>();            using (var reader = ExecuteDataReader(sql, commandType, parameters))            {                while (reader.Read                {                    var entity = new T();                    foreach (var propertyInfo in props)                    {                        var schemaTable = reader.GetSchemaTable();                        if (schemaTable == null)                            return new List<T>();                        schemaTable.DefaultView.RowFilter = $"ColumnName='{propertyInfo.Name}'";                        if (schemaTable.DefaultView.Count <= 0) continue;                        if (!propertyInfo.CanWrite)                            continue;                        var val = reader[propertyInfo.Name];                        if (val != DBNull.Value)                            propertyInfo.SetValue(entity, val);                    }                    list.Add;                }            }            return list;        }

  不难剖判应用反射的代码:

    type.GetProperties():获取属性集结;

    propertyInfo.CanWrite:可写属性;

    propertyInfo.SetValue(entity,
val):属性赋值,选择相应的靶子开展赋值。


反骨仔

微软官方文书档案

为此,不论什么事,过度了,总不是好事。


本篇小说首要介绍C#反射【用法】。

反射是架设师必会的根基,因为其他八个被设计出来的框架,都要选取反射。

反射也是最掩饰的语法,因为反射写出来后,经常它会被向来封装,然后调用者就只承担利用,不再关怀她的切实可行落到实处。

那与它的性状有关,因为反射正是为着削减代码冗余而留存的,所以,看不见很正规。

反射的定义

官方概念:反射提供了包装程序集、模块和类别的对象(Type 类型)。能够运用反射动态创立类型的实例,将项目绑定到现存对象,或从现有对象得到项目并调用其方法或访谈其字段和总体性。若是代码中选取了质量,能够采用反射对它们进行访谈。

看不懂?不妨,我们把它翻译中年人类可通晓的语言。

C#编制程序语言中,最常使用的是类和类中的函数和性质。正向调用的诀要是,创制类,然后用类创制一个对象。接下来就足以用那几个目的调用类中的方法和质量了。

而反射,就是相对于这种正向调用的存在。即,它是反向调用。

反射能够通过类名的字符串来创立类,能够经过函数名的字符串和属性名的字符串,来调用类下的函数和质量。

有同学会问了, 既然正向能够调用,那么反向调用干什么呢?

会有这种难点的同学,先别焦急,继续往下看,反射既然存在,就一定有存在的道理。

反射的底子运用

1,类反射

先看上边代码;代码为通过类名称的字符,反射出类的对象。

public class ReflectionSyntax
{ 
    public static void Excute()
    {
        Type type = GetType("Syntax.Kiba");
        Kiba kiba = (Kiba)Activator.CreateInstance(type);
        Type type2 = GetType2("Syntax.Kiba");
        Kiba kiba2 = (Kiba)Activator.CreateInstance(type2);
    }
    public static Type GetType(string fullName)
    {
        Assembly assembly = Assembly.Load("Syntax");
        Type type = assembly.GetType(fullName, true, false);
        return type;
    }

    public static Type GetType2(string fullName)
    {
        Type t = Type.GetType(fullName);
        return t;
    } 
} 
public class Kiba
{ 
    public void PrintName()
    {
        Console.WriteLine("Kiba518");
    } 
} 

在代码中大家来看,反射时传递了字符串”Syntax.Kiba”,然后通过深入分析字符串,获取到了该字符串对应的类的品种,最终再借助Activator来救助创造类的实例。

内部字符串”Syntax.Kiba”是三个完全限定名。什么是全然限定名?完全限定名正是命名空间+类名。在反射的时候,需求大家传递完全限定名来分明毕竟要去哪个命名空间,找哪位类。

在代码中大家还足以观察,获取项目标不二等秘书籍有三种,一种是较复杂的,一种是简约的。

GetType2方法是简轻易单的拿走项目,通过Type间接就剖析了字符串。而GetType则先举办了加载Assembly(组件),然后再由组件获取项目。

互相有何样分别呢?

有别于是,用Type直接分析,只好深入分析当前命名空间下的类。假如此类存在于引用的DLL中,就深入分析不了。

而GetType方法中的[Assembly.Load指定了程序集名],所以,在反射时,就能够去钦点的命名空间里找对应的类。那样就能够找到非本主次集下的类了。

[Assembly.Load钦命了前后相继集名]那句话糟糕明白?

举重若轻,换个表明,Assembly.Load内定了命名空间的称呼,所以反射时,会去这么些命名空间里找类,那样是否就好精通了。

Assembly

Assembly的留存让反射变得专程灵巧,个中Assembly.Load不仅仅能够导入大家引进的程序集(或命名空间)。

也得以导入我们未引进程序集的dll。调用情势如下:

System.Reflection.Assembly o = System.Reflection.Assembly.Load("mscorlib.dll");

Assembly导入了前后相继集后,还是能不借助Activator来协理,自个儿就能够创设类。如下:

Assembly assembly = Assembly.Load("Syntax");
Kiba kiba = (Kiba)assembly.CreateInstance("Syntax.Kiba");

局地同学恐怕会顾忌品质,会以为这么反射,会使程序变慢。

有这种主见的同窗,其实您早已是在过度驾驭语法了。这种地点的代码质量其实是能够不用关爱的。

那正是说,到底会不会变慢呢?

答案是那样的,纵然你是运用完全限定名来反射,速度就是一样的。如若是反射时,只写了贰个类名,那么速度就能变慢。因为它要遍历全数的命名空间,去找这么些类。

即,只要反射时把类的命名空间写全,那么速度就不会慢。

2,函数反射

函数的反光应用关键是采纳类MethodInfo类反射,上面先看下基础应用。

public static void ExcuteMethod()
{ 
    Assembly assembly = Assembly.Load("Syntax"); 
    Type type = assembly.GetType("Syntax.Kiba", true, false);
    MethodInfo method =  type.GetMethod("PrintName"); 
    object kiba = assembly.CreateInstance("Syntax.Kiba");
    object[] pmts = new object[] { "Kiba518" };
    method.Invoke(kiba, pmts);//执行方法  
}
public class Kiba
{
    public string Name { get; set; }
    public void PrintName(string name)
    {
        Console.WriteLine(name);
    }
}

有些同班第一立即上去只怕会有点不适于,因为临近非常多类都以大家有的时候常用的。那也不能,因为那是贰个晋级的经过,必得经历从面生到熟稔。当您熟谙了那般的代码后,就表示你的技能水平又升高了二个台阶。

上边解说一些那个代码。

首先大家导入了命名空间,接着我们赢得了该命名空间下Kiba那些类的门类;接下去大家透过那一个项目来获取钦命名称的函数。

下一场我们因此Assembly成立了一个Kiba的实例,接着定义了一个参数的Object数组,因为Kiba类下的函数PrintName唯有一个参数,所以,我们只为那么些Object数组增多二个指标[Kiba518]。

最终,大家由此method.Invoke来调用这一个函数,由于是反光,所以调用时,须求钦点Kiba类的实例对象和入参。

如此那般,函数的反光就落到实处了。

3,属性反射

属性反射是用PropertyInfo类来兑现,下边看基础的天性反射。

public static void ExcuteProperty()
{
    Kiba kiba = new Kiba();
    kiba.Name = "Kiba518";
    object name = ReflectionSyntax.GetPropertyValue(kiba, "Name");
    Console.WriteLine(name); 
} 
public static object GetPropertyValue(object obj, string name)
{
    PropertyInfo property = obj.GetType().GetProperty(name);
    if (property != null)
    {
        object drv1 = property.GetValue(obj, null);
        return drv1;
    }
    else
    {
        return null;
    } 
}

如代码所示,首先大家定义了二个Kiba的目的,并为Name赋值,然后咱们透过GetPropertyValue方法,传递了Kiba对象和要博取值的属性名称。

GetPropertyValue函数里通过动用PropertyInfo完结了反光。

局地同学或然会感到,这几个很鸡肋,既然已经收获指标,还反射做什么样,直接获得就可以了啊。

别焦急,大家接下去一同看反射的框架结构应用。

反射的架构应用

 框架编写的骨干目标之一,是联合系统秩序。那么怎样是系统秩序呢?

 首先大家看下系统的组合,系统个平日是由子系统,程序集,类,函数那四有的组成。如下图所示。

银河国际点击登录 1

既是系统由子系统,程序集,类,函数那多少个基础成分结合,那么系统秩序,自然指的就是那八个因素的秩序。而那多少个要素最难产生秩序的就是函数了。

很断定,任何的品种都留存重复的函数,恐怕作用类似的函数。而根本杜绝这种情状,明显是不容许的。那么大家只能硬着头皮是设计会防止双重成分的框架了。而反射,便是为此而存在的。

反射的架构应用

具体中的框架因为那样那样的源委,会有美妙的安排性,所以拘泥于一种设计情势是愚拙的,实战中要出头设计情势一齐行使,局部设计不经常只取设计方式中一部分也能够。那样才干兑现项目标量身定制。

就此,这里只介绍一种实战的架构应用,一种选择反射的框架基础结构。下边请框架基础代码。

public class Client
{
    public void ExcuteGetNameCommand()
    {
        Proxy proxy = new Proxy();
        GetNameCommand cmd = new GetNameCommand();
        ResultBase rb = proxy.ExcuteCommand(cmd);
    } 
} 
public class Proxy
{
    public ResultBase ExcuteCommand(CommandBase command)
    {
        var result = HandlerSwitcher.Excute(command);
        return result as ResultBase;
    }
}
public class HandlerSwitcher
{
    private const string methodName = "Excute";//约定的方法名
    private const string classNamePostfix = "Handler";//约定的处理Command的类的名称的后缀 
    //获取命名空间的名称
    public static string GetNameSpace(CommandBase command)
    {
        Type commandType = command.GetType();//获取完全限定名
        string[] CommandTypeNames = commandType.ToString().Split('.');
        string nameSpace = "";
        for (int i = 0; i < CommandTypeNames.Length - 1; i++)
        {
            nameSpace += CommandTypeNames[i];
            if (i < CommandTypeNames.Length - 2)
            {
                nameSpace += ".";
            }
        } 
        return nameSpace;
    }

    public static object Excute(CommandBase command)
    {
        string fullName = command.GetType().FullName;//完全限定名
        string nameSpace = GetNameSpace(command);//命名空间  
        Assembly assembly = Assembly.Load(nameSpace);
        Type handlerType = assembly.GetType(fullName + classNamePostfix, true, false);
        object obj = assembly.CreateInstance(fullName + classNamePostfix);
        MethodInfo handleMethod = handlerType.GetMethod(methodName);//获取函数基本信息
        object[] pmts = new object[] { command }; //传递一个参数command
        try
        {
            return handleMethod.Invoke(obj, pmts);
        }
        catch (TargetInvocationException tie)
        {
            throw tie.InnerException;
        }
    }
}
public class GetNameCommandHandler
{
    public ResultBase Excute(CommandBase cmd)
    {
        GetNameCommand command = (GetNameCommand)cmd;
        ResultBase result = new ResultBase();
        result.Message = "I'm Kiba518";
        return result;
    }
}
public class GetNameCommand: CommandBase
{  
} 
public class CommandBase
{ 
    public int UserId { get; set; } 

    public string UserName { get; set; } 

    public string ArgIP { get; set; } 
}
public class ResultBase
{ 
    public string Message { get; set; } 
}

代码中框架很简短,首要目标是落到实处叁个代理,用于拍卖承袭了CommandBase的类的代理。

即,客商端,不论传来什么样的Command,只要它是三番两次自CommandBase的,那个代理都会找到呼应的拍卖类,并试行管理,且重临结果。

为了更清楚的知情这段代码,大家能够参谋下边这几个流程图。结合了图片在来看代码,架构就能够更清晰。

银河国际点击登录 2

其一大致的框架中,使用了贰个定义,叫做约定优先条件,也堪当约定优于配备;喜欢概念的同伙能够自动百度。

框架中利用的四个约定如下:

率先个是,管理Command的类必得后缀名是Command的类名+Handler结尾。

第二个是,管理Command的类中的管理函数名必得为Excute。

实际上概念正是供我们使用的,会用就可以;学习的进度中,概念之类的术语,有个影象就能够。

PS:为了阅读方便,那当中的类都聚焦写在了三个命名空间之下了,借使有想选拔这种设计形式的校友,请遵照本身项目所需举办扩充。


与上述同类,我们就通过反射完结了一个百般简便的框架,通过应用那些框架,会让代码变的进一步简洁。

而为了落实每一个模块的不难,反射也将会被封装在相继模块的平底,所以,反射无庸置疑,正是框架设计的功底。

反射与特色

反射在系统中另多个根本应用正是与特点的组成使用。

在一部分周旋复杂的连串中,难免会蒙受一些场景,要讲对象中的一有的属性清空,或然要取得对象中的某个质量赋值。常常大家的兑现形式正是手写,一个几个的赋值。

而采纳反射并组成性子,完全可以简化这种复杂操作的代码量。

 public partial class ReflectionSyntax
 {
     public void ExcuteKibaAttribute()
     {
         Kiba kiba = new Kiba();
         kiba.ClearName = "Kiba518";
         kiba.NoClearName = "Kiba518";
         kiba.NormalName = "Kiba518";
         ClearKibaAttribute(kiba);
         Console.WriteLine(kiba.ClearName);
         Console.WriteLine(kiba.NoClearName);
         Console.WriteLine(kiba.NormalName);
     }
     public void ClearKibaAttribute(Kiba kiba)
     {
         List<PropertyInfo> plist = typeof(Kiba).GetProperties(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public).ToList();//只获取Public的属性
         foreach (PropertyInfo pinfo in plist)
         {
             var attrs = pinfo.GetCustomAttributes(typeof(KibaAttribute), false);
             if (null != attrs && attrs.Length > 0)
             { 
                 var des = ((KibaAttribute)attrs[0]).Description; 
                 if (des == "Clear")
                 {
                     pinfo.SetValue(kiba, null); 
                 }
             }
         }
     } 
 } 
 public class Kiba
 {
     [KibaAttribute("Clear")]
     public string ClearName { get; set; }
     [KibaAttribute("NoClear")]
     public string NoClearName { get; set; }
     public string NormalName { get; set; }

 }
 [System.AttributeUsage(System.AttributeTargets.All)]
 public class KibaAttribute : System.Attribute
 {
     public string Description { get; set; }
     public KibaAttribute(string description)
     {
         this.Description = description;
     }
 }

如上述代码所示, 大家透过反射,将富有KibaAttribute天性的,且描述为Clear的属性,清空了。

理之当然为了叁性情能这么做不值得,但一旦二个对象有72个本性的时候,这么做就值得了。

既然如此能免去属性的数量,那么自然就足以为属性赋值。至于哪些促成反射赋值,相信我们能够举一个例子就类推其余的。

反射+本性最广大的场馆

反射+特性一齐行使,最广大的气象就是用ADO.NET从数据库查询出DataTable的数码,然后将DataTable的数额调换到Model实体类型。

咱俩在支付中,为了让实体尤其充血,往往会对数据实体扩大一些天性和办法。(什么是充血?充血正是充血模型,有意思味的同桌能够自动百度询问下,轻巧说便是为实体加属性和艺术。)

那么,在用反射,将DataTable转存到Model实体的时候,遍历属性并赋值的时候,就能够多遍历那么一回。

万叁只是一个实体,那么,多遍历五回也没影响。但,要是是数八万的数码,这那多五遍的遍历影响就大了。

而用反射+天性,就足以削减那么些额外遍历次数。

银河国际点击登录,讲了这么多为何不给代码呢?

因为小编感觉,将方面包车型地铁内容全知晓的同学,应该能够说,已经框架启蒙了。那么,那些反光+脾气的DataTable转数据实体,借使能团结写出来,就终于框架入门了。所以,这里给大家留下了多少个练兵的空中。

小心,作者那边说的是框架,并非架设。

框架与架构的区分是那样的,框架是个名词,而架构是个动词。框架就算很熟习了,也错失得能够架构的很好。这么些我们要么要留意区分。

结语

看完了整篇小说,有的同学恐怕会有疑问,这么生疏的PropertyInfo和MethodInfo真的有人会用吗?都是Copy代码,然后利用啊。

答案是,当然有人能够熟习应用。反射是架构师的入门基础,任何贰个[可以实战]的架构师,都急需任何时间任何地方的能够手写出反射,因为优化框架是他俩的权责。

故此,对此有所疑虑的朋侪,能够大力演练了,将委托融入血液,是高端软件技术员的功底,而将反射融合血液,正是架构师的底子了。

C#语法——元组类型

C#语法——泛型的有余选用

C#语法——await与async的不利张开药格局

C#语法——委托,架构的血流

C#语法——事件,逐步边缘化的四弟。

C#语法——音讯,MVVM的宗旨才具。

我对C#的认知。


注:此小说为原创,款待转发,请在篇章页面显然位置给出此文链接!
若你以为那篇作品还不易,请点击下右下角的【推荐】,特别多谢!
要是您认为这篇小说对你抱有帮助,那就无妨支付宝小小打赏一下呢。 

银河国际点击登录 3

 

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*
*
Website