c#中的反射

都说c#和java差不多,会了java,c#基本都会了。我对java还是很熟的,对oc也比较熟,但是c#感觉还是过一遍比较好。最近看到了c#的反射,这里呢就对反射在各个语言中的体现横向比较一下。

反射,让程序员能够根据一个字符串去:

  1. 实例化对象
  2. 调用想要的方法
  3. 遍历类中或者对象中的属性或者属性值。

意思就是能够动态调用。这样会有非常非常大的好处,以及便捷性。反射这一套东西在开发业务中不是必须的,但是如果你想让你的代码有:

  1. 更好的组织性
  2. 更松的耦合性
  3. 更强的复用性

反射必须掌握。而且语言之间都是相通的。如果你是一个想偷懒的程序员,一定要掌握反射。

1.如何从一个字符串实例化一个类

c#

Type type = Type.GetType("Person",true);
Person p =  (Person)System.Activator.CreateInstance(type);

java

 Object o = Class.forName("com.company.Main").newInstance();

oc

Class class = NSClassFromString(@"YXTestObject");
YXTestObject *obj= [[class alloc] init];
或者
Class class = objc_getClass("YXTestObject");
 YXTestObject *obj= [[class alloc] init];

js

//js就比较灵活一点

//第一种方式:这种方式有一定的不安全性,特别是当类名从用户那边获取的时候
var myStr = "Product"
var p = eval("new " + myStr + "()");

//第二种:将类定义在一个域中
var mynamespace = {};
mynamespace.Person = function Person() {..}
var p = new mynamespace["Person"]();

//如果直接定义在全局域可以这样:
var p = new window["Person"]();

2.如何通过一个字符串调用某个对象的某个方法

c#

Person p = new Person();

//有参公有
var methodInfo =   p.GetType().GetMethod("set_Name");
methodInfo.Invoke(p, new string[] {"aaa"});

//无参公有
var methodInfo2 = p.GetType().GetMethod("get_Name");
var  name =  methodInfo2.Invoke(p, null);

//静态函数公有
p.GetType().GetMethod("getaaa").Invoke(null,null)

//非静态私有
var methodInfo2 = p.GetType().GetMethod("getaaa",BindingFlags.NonPublic | BindingFlags.Instance);
var  result =  methodInfo2.Invoke(p, null);

//静态私有
 var methodInfo2 = p.GetType().GetMethod("getaaa",BindingFlags.NonPublic | BindingFlags.Static);
 var  name =  methodInfo2.Invoke(p, null);

java

//公有
Person p =(Person) Class.forName("com.company.Person").newInstance();
String number =   (String)Person.class.getMethod("getNumber", null).invoke(p,null);

//私有
Person p =(Person) Class.forName("com.company.Person").newInstance();
Method method =   Person.class.getDeclaredMethod("getNumber", null);
method.setAccessible(true);
String number=(String)method .invoke(p,null);

//Java中反射静态方法和调用普通的公有私有方法无太大区别
//只是忽略了invoke中的对象参数
//getDeclaredMethod方法可以获取当前类的所有方法
//但是不包含继承的方法,如果想获取继承的方法,可以通过getSuperclass向上寻找。
//getMethod方法只会获取public类型的

oc

//方式1:这种方式,最多支持2个参数
NSString *number = [obj performSelector:NSSelectorFromString(@"getNumber") withObject:nil withObject:nil];
//方式2
//支持多参
//导入#import <objc/message.h>
//Build Setting--> Apple LLVM 6.0 - Preprocessing--> Enable Strict Checking of objc_msgSend Calls  改为 NO
//否则会报Too many arguments to function call ,expected 0,have3
NSString *number2 = objc_msgSend(obj,NSSelectorFromString(@"getNumber"),nil);

//类方法
NSString *number2 = objc_msgSend(class,NSSelectorFromString(@"getNumber"),nil);

//NSSelectorFromString(@"getNumber")等价于sel_registerName("getNumber")

//上面的几种方式不管在h文件中有没有声明都能被调用到

js

//js就非常简单了
var p = new Person();
var number = p["getNumber"]();

3.通过属性名称字符串获取某个对象的字段值

c#

//公有
p.GetType().GetField("number").SetValue(p,"123456");

//私有
p.GetType().GetField("number",BindingFlags.NonPublic|BindingFlags.Instance).SetValue(p,"123456");

//私有静态
p.GetType().GetField("number",BindingFlags.NonPublic|BindingFlags.Static).SetValue(p,"123456");

Java

  Field field  =  Person.class.getDeclaredField("name");
 field.setAccessible(true);  //是否设置强制访问私有
 field.set(p, "aaaa");          //设置字段值
 String name = (String)field.get(p);  //获取字段值

oc

//可以通过kvc的方式,成员变量不管被声明在m文件还是h文件
//不管是私有还是公有都能通过这种方式被访问到
 YXTestObject *obj= [[class alloc] init];
[obj setValue:@"男" forKey:@"sex"];
NSLog(@"%@",[obj valueForKey:@"sex"]);

js

js依然是最简单的
var p =  new Person();
p["number"]="123456";
var number= p["number"];

4.遍历某个对象的字段以及字段值

c#

public class Test {        
public static void reflect(Object o){  
  
    PropertyInfo[] propertys = o.GetType().GetProperties();  
    foreach (PropertyInfo pinfo in propertys)  
    {  
        Console.WriteLine(pinfo.Name+","+pinfo.GetValue(o,null));  
    }  
}  
static void Main(string[] args){  
    Person p = new Person();  
    reflect(p);  
}  

}

java

public class Test {        
public static void reflect(Object o) throws Exception{  
    Class cls = o.getClass();  
    Field[] fields = cls.getDeclaredFields();  
    for(int i=0; i<fields.length; i++){  
        Field f = fields[i];  
        f.setAccessible(true);  
        System.out.println("属性名:" + f.getName() + " 属性值:" + f.get(o));  
    }   
}  
public static void main(String[] args) throws Exception{  
    Person p = new Person();  
    reflect(p);  
}  

}

oc

+(NSString*)reflectWithObj:(id)obj
{
    NSString *name = nil;
    NSString *value =nil;
    uint32_t ivarCount;

    Ivar *ivars = class_copyIvarList([obj class], &ivarCount);
    
    if(ivars)
    {
        for(uint32_t i=0; i<ivarCount; i++)
        {
            Ivar ivar = ivars[i];
            
            name = [NSString stringWithUTF8String:ivar_getName(ivar)];
            value=[obj valueForKey:name];
            NSLog(@"name=%@,value=%@",name,value==nil?@"nil":value);
        }
        
        free(ivars);
    }

    return name;
}   

Js

function allPrpos ( obj ) {   
    var props = "" ;   
    for ( var p in obj ){   
        if ( typeof ( obj [ p ]) == " function " ){   
        obj [p]() ;   
        } else {   
            props += p + " = " + obj [ p ] + " \t " ;   
        }   
    }   
    console.log( props ) ;   
}

c#中类似的还有

  1. 获取某个类的ConstructorInfo(构造器信息): 通过GetConstructors或者GetConstructor方法。

  2. 获取某个类的EventInfo(类中的事件信息):通过GetEvents或者GetEvent方法。

  3. 获取某个类的PropertyInfo(类中的属性信息):通过GetProperties或者GetProperty方法。

  4. 如何加载程序集

    Assembly.Load("相对路径");
    Assembly.LoadFrom("完整路径");

  5. 如何取得程序集中所有的Type

    Type[] types = Assembly.Load("aaa").GetTypes();

Java中也有类似的反射方法,以获取构造器,等类中的一些定义属性。
OC 是动态语言就反射来说效率会高于静态语言java和c#。
Javascript总的来说是最灵活的。

反射还有很多,这里就不一一赘述,总的来说使用率比较高的就是我介绍的这几个。当然实际肯定还有各种各样的需求,慢慢查api吧,总结是总结不完的,这里只是把常用的列出来。

PS:写代码这么久了,还没有像样的博客,之前建了三次,忘了三次都被阿里云最后回收了。这次换社区试试,希望能坚持下去。会把以前的笔记,经验,还有工作中的一些问题,总结一下,慢慢的放到博客上。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容