【澳门新萄京】架构师的入门基础

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

反射的简单用法

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

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

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

有的同学可能会担心性能,会觉得这样反射,会使程序变慢。

优缺点

  优点:

  1. 提高了程序的灵活性和扩展性;
  2. 降低耦合性;
  3. 它允许程序创建和控制任何类的对象,无需提前硬编码目标类。

  缺点:

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

有兴趣是好事,但就算知道了反射的本质,了解了反射是如何设计的,你技术也没什么质的改变。因为,技术水平最终还是要落实到应用上。

反射的类型成员信息

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

  • Module:模块信息(如包含模块的程序集和模块中的类)。

  • ConstructorInfo:构造函数信息(如名称、参数、访问修饰符等)。
  • MethodInfo:方法成员信息(如名称、返回类型、参数和访问修饰符等)。

  • FieldInfo:字段成员信息(如名称、访问修饰符)。

  • EventInfo:事件成员信息(如名称、事件处理程序的数据类型、自定义特性、声明类型以及事件的反射的类型)。

  • PropertyInfo:属性成员信息(如名称、数据类型、声明类型,反射的类型和属性的只读或可写状态),并获取或设置属性值。

  • ParameterInfo:参数成员信息(如参数名、数据类型以及参数在方法签名中的位置等)。

  • CustomAttributeData:自定义特性信息。

  System.Reflection.Emit命名空间的类提供一种专用形式的反射,使你能够在运行时生成类型。

看不懂?没关系,我们把它翻译成人类可理解的语言。

一个常见的示例用法

  我们一开始学习三层架构的时候,都应该会自己跟着老师动手打造一个
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#语法——委托,架构的血液

简介

  反射是
.NET中的重要机制,通过反射,可以在运行时获得程序或程序集中类型(包括
class、struct、delegate、interface 和 enum 等)的成员和成员的信息。

  通过反射,即可对每一种类型了如指掌,并且也可以通过反射创建、调用和访问对象,即便在编译时不确定该对象的类型。

  程序集包含模块,模块包含类型,而类型包含成员。反射提供封装程序集、模块和类型的对象。可以使用反射动态地创建类型的实例,将类型绑定到现有对象,或从现有对象中获取类型。

反射可以通过类名的字符串来创建类,可以通过函数名的字符串和属性名的字符串,来调用类下的函数和属性。

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

一些同学第一眼看上去可能会有点不适应,因为好像很多类都是大家不经常用的。这也没办法,因为这是一个进阶的过程,必须经历从陌生到熟悉。当你熟悉了这样的代码后,就代表你的技术水平又进步了一个台阶。

如代码所示,首先我们定义了一个Kiba的对象,并为Name赋值,然后我们通过GetPropertyValue方法,传递了Kiba对象和要获取值的属性名称。

有的同学可能会觉得,这个很鸡肋,既然已经得到对象,还反射做什么,直接获取就可以了呀。

所以,这里只介绍一种实战的架构应用,一种使用反射的框架基础结构。下面请框架基础代码。

反射也是最隐蔽的语法,因为反射写出来后,通常它会被直接封装,然后调用者就只负责使用,不再关注他的具体实现。

如果只是一个实体,那么,多遍历几次也没影响。但,如果是数十万的数据,那这多几次的遍历影响就大了。

 框架编写的核心目的之一,是统一系统秩序。那么什么是系统秩序呢?

这个简单的框架中,使用了一个概念,叫做约定优先原则,也叫做约定优于配置;喜欢概念的小伙伴可以自行百度。

反射的架构应用

最后,我们通过method.Invoke来调用这个函数,由于是反射,所以调用时,需要指定Kiba类的实例对象和入参。

这样,我们就通过反射实现了一个非常简约的框架,通过使用这个框架,会让代码变的更加简洁。

反射的定义

C#语法——泛型的多种应用

反射的架构应用

函数的反射应用主要是使用类MethodInfo类反射,下面先看下基础应用。

当然为了一个属性这么做不值得,但如果一个对象有70个属性的时候,这么做就值得了。

[Assembly.Load指定了程序集名]这句话不好理解?

C#语法——事件,逐渐边缘化的大哥。

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

别着急,我们接下来一起看反射的架构应用。

其中字符串”Syntax.Kiba”是一个完全限定名。什么是完全限定名?完全限定名就是命名空间+类名。在反射的时候,需要我们传递完全限定名来确定到底要去哪个命名空间,找哪个类。

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

那么,到底会不会变慢呢?

答案是这样的,如果你是使用完全限定名来反射,速度就是一样的。如果是反射时,只写了一个类名,那么速度就会变慢。因为它要遍历所有的命名空间,去找这个类。

在一些相对复杂的系统中,难免会遇到一些场景,要讲对象中的一部分属性清空,或者要获取对象中的某些属性赋值。通常我们的实现方式就是手写,一个一个的赋值。

答案是,当然有人可以熟练应用。反射是架构师的入门基础,任何一个[可以实战]的架构师,都需要随时随地的可以手写出反射,因为优化框架是他们的责任。

编程其实就是写代码,而写代码目的就是实现业务,所以,语法和框架也是为了实现业务而存在的。因此,不管多么高大上的目标,实质上都是业务。

C#语法——await与async的正确打开方式

 首先我们看下系统的构成,系统个通常是由子系统,程序集,类,函数这四部分构成。如下图所示。

反射在系统中另一个重要应用就是与特性的结合使用。

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

反射+特性一起应用,最常见的场景就是用ADO.NET从数据库查询出DataTable的数据,然后将DataTable的数据转换成Model实体类型。

我对C#的认知。

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

区别是,用Type直接解析,只能解析当前命名空间下的类。如果该类存在于引用的DLL中,就解析不了。

Assembly导入了程序集后,还可以不借助Activator来辅助,自己就可以创建类。如下:

C#语法——消息,MVVM的核心技术。

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

然后我们通过Assembly创建了一个Kiba的实例,接着定义了一个参数的Object数组,因为Kiba类下的函数PrintName只有一个参数,所以,我们只为这个Object数组添加一个对象[Kiba518]。

属性反射是用PropertyInfo类来实现,下面看基础的属性反射。

这与它的特性有关,因为反射就是为了减少代码冗余而存在的,所以,看不见很正常。

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

看完了整篇文章,有的同学可能会有疑问,这么生疏的PropertyInfo和MethodInfo真的有人会用吗?都是Copy代码,然后使用吧。

GetType2方法是简单的获取类别,通过Type直接就解析了字符串。而GetType则先进行了加载Assembly(组件),然后再由组件获取类型。

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

在代码中我们看到,反射时传递了字符串”Syntax.Kiba”,然后通过解析字符串,获取到了该字符串对应的类的类型,最后再借助Activator来辅助创建类的实例。

没关系,换个表达,Assembly.Load指定了命名空间的名称,所以反射时,会去这个命名空间里找类,这样是不是就好理解了。

既然系统由子系统,程序集,类,函数这四个基础元素构成,那么系统秩序,自然指的就是这四个元素的秩序。而这四个元素最难形成秩序的就是函数了。

即,客户端,不论传来什么样的Command,只要它是继承自CommandBase的,这个代理都会找到对应的处理类,并执行处理,且返回结果。

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

发表评论

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