天天看点

反射之动态创建对象前言讨论拓展总结 补充1 补充2

C#有关反射的话题已经是个老生常谈的话题,也许园友一看这标题都不屑去看了,但是既然拿出来讲必有讲之道理,当然,不喜勿喷,高手请绕道!直入话题。

那么现在怎么动态获取该对象并打印该对象?啊,用反射动态获取呗,ok,实现如下!

完全没错,在黑框框中运行输出入下:

反射之动态创建对象前言讨论拓展总结 补充1 补充2

此时我们再来运行看看!!什么鬼,怎么出现错误了???

反射之动态创建对象前言讨论拓展总结 补充1 补充2

吓我一跳,平常来个未将对象设置到对象的实例那是见怪不怪了,出现这个容我想想,无参构造函数似乎暗示着什么,突然醒悟对象不都默认有个无参的构造函数吗,啊,shit,原来是因为我定义了一个有参数的构造函数,用Activator.CreateInstance动态创建对象调用的无参构造函数啊,紧接着我将鼠标放在该方法跟前,都告诉我了写着 使用指定类型的默认构造函数来创建该类型的实例 ,知道错误所在了,关键是怎么去解决,要是类中写了有参数的构造函数,现在想要反射来动态创建对象岂不是不能够了吗?继续想,记得在javascript中虽然不能够像C#实现重载,当然js也不存在重载,但是可以根据arguments.length来近似于实现所谓的重载,这里同样可不可以根据构造函数的个数来实现呢?有了这个想法就开干,当看到这个GetConstructors方法心底就舒坦起来了,经过反复查看其方法改造控制台后的代码如下:

 现在获取到了构造函数的长度即可以根据参数的个数来进行创建对象,离解决问题更进一步了,这时我想到如果我参数个数相同,怎么知道我是调用哪个构造函数呢?对,根据参数的类型,所以现在问题上升到怎么确定我要传递参数的类型呢?看看构造函数的属性  ConstructorInfo 中有没有什么方法可以定义参数类型,皇天不负有心人 GetConstructor 方法参数中 有个Type 这就是参数的类型了,然后利用 Invoke 委托对构造函数传入参数获取对象,如下:

 同样得到上述结果打印出:反射之动态创建对象.Person,ok,终于解决了,完美!

在上述过程中用到委托Invoke再传入参数到其中,鉴于此对于反射,参考代码改善建议利用dynamic关键字简化反射实现。下面用例子说明,利用反射计算Person类中方法计算两个数的和。利用反射立马能够写出

如果利用 dynamic 关键字能够更加精简而且更加优美 

    【1】利用Activator.CreateInstance,前提是调用对象的默认无参构造函数

    【2】利用构造器来动态创建对象

上述提到用 dynamic 来简化反射的实现,对于园友提出 对于反射无法获取到class是什么 ,像 dynamic dy = new Person(); Person dy= new Person() ; 似乎是一样的,那还不如直接实例化调用其方法即可,一想确实是这样,经过再次研究觉得用dynamic只是更加便捷而且代码更加精简,就像用lamda简化而省去了用委托或者匿名方法一样!下面就以一个实例来说明不得不用反射来实现,还用上面的Person类,现在继续添加一个 OtherPerson 类:

然后在Person类中添加一个返回值为OtherPerson的私有方法 GetOtherPerson 

现在想调用 GetOtherPerson 方法获取 OtherPerson 类中的私有字段 OtherAge  ,别告诉我直接实例化Person对象,再调用,因为是私有现在无法实现,所以马上想到的是通过反射来实现获取这个方法再同样实现获取私有字段

一大片代码看起来是不是很恶心,接下来我们将代码进行改进,使其便捷化,上述提到用dynamic来实现,所以就来吧!

  var age = ((dynamic)p1).GetOtherPerson().OtherAge; 就一行代码是不是很简单,再次说明了dynamic的优美和简洁,so  perfect!那我们运行下看看吧,oh,往往在你最得意的时候结果就会给你当头一棒,出错了!如下

反射之动态创建对象前言讨论拓展总结 补充1 补充2

这保护的级别有点忒高,那必须攻破你的堡垒!弄了一下午最终还是google给出了一位前辈已经这么做过的解决方案!重写了dynamic的基类DynamicObject,接着就写了它的扩展方法,代码如下:

扩展方法如下

最后调用拓展方法  var age = p1.AsDynamic().GetOtherPerson().OtherAge; 成功!所以有时候使用dynamic使得代码变得更加优美而用反射代码繁多而且显得非常臃肿,通过再一次学习dynamic,对此也深信不疑!