C#语法——反射,架构师的入门基础。

前言

编制程序其实正是写代码,而写代码指标正是实现工作,所以,语法和框架也是为了兑现业务而存在的。因而,不管多么巨大上的指标,实质上都以业务。

所以,作者觉着毫无把写代码回升到正确的中度。回涨到点子就足以了,因为艺术本人也尚未低度。。。。

软件设计存在过度设计,语法和框架的明亮,也设有过度精通。比如,反编写翻译下,看看反射是怎么落到实处的。。。

有趣味是好事,但哪怕知道了反光的精神,通晓了反光是如何规划的,你技术也没怎么质的更改。因为,技术水平最终照旧要落到实处到应用上。

在诸如,过度的言情代码质量,也不见得是一件好事,因为,[大多数]状态下,硬件比程序员便宜多了。。。(注意那里指的是代码不是算法和数据库品质)

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


本篇文章重要介绍C#反射【用法】。

反射是架设师必会的底子,因为别的3个被设计出来的框架,都要选拔反射。

反射也是最隐蔽的语法,因为反射写出来后,日常它会被直接封装,然后调用者就只负责运用,不再关心她的求实达成。

这与它的特点有关,因为反射正是为着削减代码冗余而存在的,所以,看不见很正规。

反射的概念

法定概念:反射提供了打包程序集、模块和项目标对象(Type 类型)。可以动用反射动态创立类型的实例,将品种绑定到现有对象,或从现有对象得到项目并调用其模式或访问其字段和性质。假设代码中应用了质量,能够利用反射对它们举行走访。

ca88官网,看不懂?没关系,大家把它翻译成人类可清楚的语言。

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”是3个全然限定名。什么是全然限定名?完全限定名就是命名空间+类名。在反射的时候,需求大家传递完全限定名来分明毕竟要去哪个命名空间,找哪位类。

在代码中大家还能看到,获取项目标办法有三种,一种是较复杂的,一种是大致的。

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);
    }
}

一些同校第①立立即去大概会有点不适于,因为接近很多类都是我们不平日用的。那也不能,因为那是1个进阶的经过,必须经历从素不相识到熟习。当您熟练了那般的代码后,就意味着你的技术水平又发展了三个阶梯。

上边讲解一些这几个代码。

第③大家导入了命名空间,接着大家收获了该命名空间下Kiba那些类的类型;接下去大家经过那些类型来取得钦命名称的函数。

然后大家透过Assembly创设了一个Kiba的实例,接着定义了3个参数的Object数组,因为Kiba类下的函数PrintName唯有2个参数,所以,我们只为那一个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;
    } 
}

如代码所示,首先咱们定义了1个Kiba的指标,并为Name赋值,然后大家透过GetPropertyValue方法,传递了Kiba对象和要博得值的质量名称。

GetPropertyValue函数里通过利用PropertyInfo完毕了反光。

一部分同学可能会认为,这些很鸡肋,既然已经获取指标,还反射做什么样,直接拿走就足以了呀。

别着急,大家接下去一起看反射的架构应用。

反射的架构应用

 框架编写的主导指标之一,是联合系统秩序。那么怎样是系统秩序呢?

 首先大家看下系统的整合,系统个普通是由子系统,程序集,类,函数这四有个别组成。如下图所示。

ca88官网 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; } 
}

代码中框架很简短,首要指标是贯彻1个代理,用于拍卖继承了CommandBase的类的代办。

即,客户端,不论传来什么样的Command,只要它是继续自CommandBase的,这几个代理都会找到相应的处理类,并履行拍卖,且重临结果。

为了更清晰的理解那段代码,大家能够参见上面那一个流程图。结合了图片在来看代码,架构就会更显然。

ca88官网 2

其第一次全国代表大会约的框架中,使用了一个定义,叫做约定优先条件,也称之为约定优于配备;喜欢概念的同伙能够自行百度。

框架中动用的八个约定如下:

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

第三个是,处理Command的类中的处理函数名必须为Excute。

事实上概念就是供大家使用的,会用即可;学习的历程中,概念之类的术语,有个印象即可。

PS:为了阅读方便,那中间的类都集中写在了多少个命名空间之下了,倘使有想行使这种设计情势的校友,请根据本身项目所需实行扩充。


这么,我们就由此反射实现了八个13分简便的框架,通过运用那么些框架,会让代码变的尤为简洁。

而为了促成每种模块的简练,反射也将会被封装在依次模块的最底层,所以,反射毫无疑问,正是框架设计的根基。

反射与风味

反射在系统中另四个重点应用正是与特色的结合使用。

在部分对立复杂的类别中,难免会遭受有的光景,要讲对象中的一局地属性清空,大概要博取对象中的有些质量赋值。日常我们的落成格局正是手写,四个四个的赋值。

而使用反射并整合特性,完全能够简化那种复杂操作的代码量。

 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的品质,清空了。

当然为了叁本特性这么做不值得,但假设一个目的有七十三个天性的时候,这么做就值得了。

既然能祛除属性的多少,那么自然就能够为属性赋值。至于哪些促成反射赋值,相信大家能够举一反三。

反射+特性最普遍的气象

反射+性情一起行使,最广大的风貌就是用ADO.NET从数据库查询出DataTable的数据,然后将DataTable的数据转换来Model实体类型。

大家在支付中,为了让实体尤其充血,往往会对数据实体增加一些属性和章程。(什么是充血?充血正是充血模型,有趣味的同学能够活动百度掌握下,简单说正是为实体加属性和格局。)

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

固然只是3个实体,那么,多遍历三次也没影响。但,如若是数100000的多寡,那那多五遍的遍历影响就大了。

而用反射+天性,就能够减去那么些额外遍历次数。

讲了这么多为啥不给代码呢?

因为自个儿以为,将地方的始末全精晓的同班,应该可以说,已经框架启蒙了。那么,这几个反光+天性的DataTable转数据实体,假设能协调写出来,即便是框架入门了。所以,那里给大家留下了二个演练的长空。

留意,笔者那里说的是框架,而不是架设。

框架与架构的分别是如此的,框架是个名词,而架构是个动词。框架固然很内行了,也不翼而飞得能够架构的很好。那么些大家要么要留心区分。

结语

看完了整篇作品,有的同学大概会有失常态,这么生疏的PropertyInfo和MethodInfo真的有人会用吗?都以Copy代码,然后选用啊。

答案是,当然有人能够熟稔运用。反射是架构师的入门基础,任何贰个[能够实战]的架构师,都亟需随时随处的能够手写出反射,因为优化框架是他俩的权利。

就此,对此负有可疑的伴儿,能够着力练习了,将委托融入血液,是高级软件工程师的功底,而将反射融入血液,正是架构师的基本功了。

C#语法——元组类型

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

C#语法——await与async的不错打开药形式

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

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

C#语法——音讯,MVVM的宗旨技术。

我对C#的认知。


注:此小说为原创,欢迎转发,请在篇章页面显然地方给出此文链接!
若你认为那篇小说勉强能够,请点击下右下角的【推荐】,非凡感激!
万一你认为那篇文章对您有所辅助,这就不妨支付宝小小打赏一下吗。 

ca88官网 3

 

相关文章