C#反射技术的简单操作(读取和设置类的属性)

首先建立一个测试的类 

复制代码代码如下:

public class MyClass 

  public int one { set; get; } 
  public int two { set; get; } 
  public int five { set; get; } 
  public int three { set; get; } 
  public int four { set; get; } 


然后编写反射该类的代码 

复制代码代码如下:

MyClass obj = new MyClass(); 
Type t = typeof(MyClass); 
//循环赋值 
int i = 0; 
foreach (var item in t.GetProperties()) 

  item.SetValue(obj, i, null); 
  i += 1; 

//单独赋值 
t.GetProperty("five").SetValue(obj, 11111111, null); 
//循环获取 
StringBuilder sb = new StringBuilder(); 
foreach (var item in t.GetProperties()) 

  sb.Append("类型:" + item.PropertyType.FullName + " 属性名:" + item.Name + " 值:" + item.GetValue(obj, null) + "<br />"); 

//单独取值 
int five = Convert.ToInt32(t.GetProperty("five").GetValue(obj, null)); 
sb.Append("单独取five的值:" + five); 
string result = sb.ToString(); 
Response.Write(result); 


测试显示结果: 
类型:System.Int32 属性名:one 值:0 
类型:System.Int32 属性名:two 值:1 
类型:System.Int32 属性名:five 值:11111111 
类型:System.Int32 属性名:three 值:3 
类型:System.Int32 属性名:four 值:4 
单独取five的值:11111111 

好了,了解了类的属性反射使用后,聪明的你可能就想到了方法也是可以这样做的,即t.GetProperties()改为t.GetMethods(),操作方法同上。

 

 

1.加载程序集的几种方式

1.自动扫描当前运行项目的bin\debug ,网站是扫描bin目录 下的Lib.dll程序集 (常用)
1.Assembly.Load("Lib");
2.指定一个绝对路径加载程序集
1.Assembly.LoadFile
2.Assembly.LoadFrom
3.获得当前 程序域中 所有的Assembly,包括GAC中的程序集
1.AppDomain.CurrentDomain.GetAssemblies();
4.可以直接通过this来获取
1.this.GetType().Assembly;
5. typeof(Form1).Assembly

2.获取类的几种方式

1.获取指定类的类型 ass.GetType("Lib.Pig");
2.获取当前所有的类(包括公有和非有) ass.GetTypes();
3.忽略类的全名的大小写 ass.GetType("Lib.pig", false, true);
4.可以typeof()关键字来获取 typeof(Form1);
5.可以通过实例的GetType()
Type type5 = this.GetType(); Form1 f1 = new Form1(); Type type6 = f1.GetType();

3.操作类中的字段

1.获取私有字段

pigtype.GetField("_name", BindingFlags.NonPublic | BindingFlags.Instance);
BindingFlags.NonPublic | BindingFlags.Instance:表示获取一个非共有的实例字段,一定是组合使用
BindingFlags.NonPublic | BindingFlags.Static:表示获取一个非共有的静态字段 ,一定是组合使用
####2.给_name字段赋值
object instance = ass.CreateInstance("Lib.Pig");
nameInfo.SetValue(instance, "八戒");

3.获取instance中的_name字段值

        object retVal = nameInfo.GetValue(instance);
        MessageBox.Show(retVal.ToString());

4.操作类的方法

1.获取方法
    pigType.GetMethod("Eat", BindingFlags.Public | BindingFlags.Instance);
2.调用方法
    mInfo.Invoke(instance, new object[] { "八戒", 500 });

5.实例化对象

1.     Assembly ass = Assembly.Load("Lib");
     ass.CreateInstance("Lib.Pig");
2.     Type pigType = ass.GetType("Lib.Pig");
     Activator.CreateInstance(pigType);//要求:必须要求类拥有无参的构造函数,否则报错
3.     ConstructorInfo cinfo = pigType.GetConstructor(new Type[] { typeof(string) });
    object pigInstance = cinfo.Invoke(new object[] { "八戒11" }); //new Pig("八戒",500)
4.    /获取pigInstance中的Name的值
    PropertyInfo nameInfo = pigType.GetProperty("Name");
     object res = nameInfo.GetValue(pigInstance)

6.Type类型中重要方法

Assembly ass = Assembly.Load("Lib");
Type pigType = ass.GetType("Lib.Pig");

//获取程序集的绝对路径
//pigType.Assembly.Location
//pigType .FullName  //Lib.Pig
//pigType.Name// Pig

//1.0 判断Pig类是否实现了Ipig接口
//1.0.1 获取IPig接口的Type
Type ipigType = ass.GetType("Lib.IPig");
//1.0.2 判断pigType是否实现了ipigType
bool isok = ipigType.IsAssignableFrom(pigType);  //true

//2.0 判断Pig类是否继承了Basepig类
Type basepigType = ass.GetType("Lib.BasePig");
bool isext = pigType.IsSubclassOf(basepigType); //true

//3.0 object instance=new Pig();
object instance = ass.CreateInstance("Lib.Pig");
pigType.IsInstanceOfType(instance); //true


如果在一个类中有一个公有字段,那么在这个类的外部我们可以*无阻的使用这个字段,但是如果给这个字段赋了一个很“离谱”的值,那这对程序可能会造成很大的影响

比如:

Class Student{

   public int Age;

}

在这个类外我们写:

Student stu =new Student();

stu.Age = 1000;

众所周知,人目前是不可能活到1000岁的,但是这样赋值编译器又不会报错(假设外部没有限制Age取值的逻辑),但是我们知道这个程序运行后的结果是有错误的

所以我们有了“属性”这个东西,代码可以这样写:

class Student{
        private int age;
 
        public int Age
        {
            get return age; }
            set {
                if (value >= 0 && value <= 100)
                {
                    age = value;
                }
                else
                {
                    throw new Exception("Age value has error.");
                }
            }
          }

 这里的value以为上下文关键字了

属性里的get,set访问器可以对字段提供一些安全保护了(个人理解为使用一些逻辑来保护字段的值为“说的过去的”)

---------------------------------------------------------------------------------------------------------------

---------------------------------------------------------------------------------------------------------------

一段总结:

//属性对外:暴露数据,数据可以是存储在字段里的,也可以是动态计算出来的

//对内:保护字段不受“非法值”污染

//一般情况下,它们都用于表示实体(对象或类型)的状态

//属性大多数情况下是字段的包装器(wrapper)

//建议:永远使用属性(而不是字段)来暴露数据,即字段永远是private或protected的

C#反射技术的简单操作(读取和设置类的属性)

上一篇:C# 压缩ZIP


下一篇:【愚公系列】2021年12月 二十三种设计模式(八)-组合模式(Composite Pattern)