1. 程式人生 > 實用技巧 >C#反射技術的簡單操作(讀取和設定類的屬性)

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取值的邏輯),但是我們知道這個程式執行後的結果是有錯誤的

所以我們有了“屬性”這個東西,程式碼可以這樣寫:

classStudent{ privateintage; publicintAge { get{returnage; } set{ if(value >= 0 && value <= 100) { age = value; } else { thrownewException("Age value has error."); } } }

 這裡的value以為上下文關鍵字了

屬性裡的get,set訪問器可以對欄位提供一些安全保護了(個人理解為使用一些邏輯來保護欄位的值為“說的過去的”)

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

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

一段總結:

//屬性對外:暴露資料,資料可以是儲存在欄位裡的,也可以是動態計算出來的

//對內:保護欄位不受“非法值”汙染

//一般情況下,它們都用於表示實體(物件或型別)的狀態

//屬性大多數情況下是欄位的包裝器(wrapper)

//建議:永遠使用屬性(而不是欄位)來暴露資料,即欄位永遠是private或protected的