C#基礎回顧(三)—索引器、委託、反射

一.前言


                                                                                      ------人生路蜿蜒曲折,獨自闖蕩

二.索引器

(1)定義:程序員

索引器是一種特殊的類成員,它可以讓對象以相似數組的形式來存取,使程序看起來更爲直觀,更容易編寫。編程

定義形式以下:數組

[修飾符] 數據類型 this[索引類型 index]app

{ide

get{//得到屬性的代碼}函數

set{//設置屬性的代碼}測試

}this

其中,修飾符包括:public,protected,private,internal,new,virtual,sealed,override, abstract,extern.spa

(2)實現Demo:插件

【單參數索引器】

static void Main(string[] args)

{

//通常索引器(參數爲int類型)

Console.WriteLine("--------------int類型做爲下標對索引器進行存儲------------------");

var worker = new IndexerWork();

worker[0] = "liupeng";

worker[1] = "zhangyonghe";

Console.WriteLine(string.Format("一號員工的名字爲:{0}", worker[0]));

Console.WriteLine(string.Format("二號員工的名字爲:{0}", worker[1]));

Console.WriteLine("--------------string類型做爲下標對索引器進行存儲---------------");

//索引器(參數爲string類型)

var ht = new IndexerWork();

ht["AA"] = "liupeng";

ht["BB"] = "zhangyonghe";

Console.WriteLine(string.Format("一號員工的名字爲:{0}", ht["AA"]));

Console.WriteLine(string.Format("二號員工的名字爲:{0}", ht["BB"]));

Console.ReadKey();

}

public class IndexerWork

{

public string[] Worker = new string[10];

private readonly Hashtable Ht = new Hashtable();

public string this[int index]

{

get { return Worker[index]; }

set { Worker[index] = value; }

}

public string this[string index]

{

get { return Ht[index].ToString(); }

set { Ht.Add(index, value); }

}

}

運行結果爲:

【多參數索引器】        

   //多參數索引器          

 var moreIndexer = new IndexerWork();          

moreIndexer[1, "AA"] = "I am work in BaiDu!";        

 moreIndexer[2, "BB"] = "I am work in LeTv";        

  Console.WriteLine(string.Format("一員工的公司爲:{0}", moreIndexer[1, "AA"]));        

  Console.WriteLine(string.Format("二員工的公司爲:{0}", moreIndexer[2, "BB"]));      

public class IndexerWork        {        

  private readonly List_stuList = new List();

  public string this[int index, string name]

{

get

{

var list = _stuList.Find(x => x.StuNo == index && x.StuName == name);

return list.ClassName;

}

set

{

_stuList.Add(new StudentInfo()

{

StuNo = index,

StuName = name,

ClassName = value

}

);

}

}

}

運行結果爲:

三.委託

(1)定義:

delegate 是表示對具備特定參數列表和返回類型的方法的引用的類型。在實例化委託時,你能夠將其實例與任何具備兼容簽名和返回類型的方法相關聯—— MSDN

就我我的理解而言,委託能夠看作一個函數的指針,能夠把一個函數做爲一個參數帶入到另外一個函數中;也就是函數能夠把本身委託給聲明的委託對象,進行一系列的操做。

 

定義形式以下:

public delegate int PerformCalculation(int x, int y);

【1】簡單委託

定義DeletegateDemo,並實現兩個方法GetStatus和GetSimpleSign,分別接受一個int類型的參數:

public class DeletegateDemo

{

public void GetStatus(int num)

{

if (num > 0)

{

Console.WriteLine("大於0");

}

else if (num < 0)

{

Console.WriteLine("小於0");

}

}

public static void GetSimpleSign(int num)

{

if (num > 0)

{

Console.WriteLine("+");

}

else if (num < 0)

{

Console.WriteLine("—");

}

}

}

可利用委託,咱們能夠講兩個方法做爲參數傳遞給委託對象,進行操做。首先在Main函數外面聲明委託對象

public delegate void GetMySignDeletegate(int num);

而後在Main函數裏面咱們能夠這樣實現:

static void Main(string[] args)

{

var signObj = new DeletegateDemo();

var mySignDelegateOne = new GetMySignDeletegate(signObj.GetStatus);

var mySignDelegateTwo = new GetMySignDeletegate(DeletegateDemo.GetSimpleSign);

mySignDelegateOne(5);

mySignDelegateTwo(-3);

Console.ReadKey();

}

運行結果爲:

【2】多播委託

委託能夠包含多個方法,這種委託稱爲多播委託。若是調用多播委託,就能夠按順序連續調用多個方法。爲此,委託的簽名必須返回void,不然就只能獲得委託調用的最後一個方法的結果。

多播委託可使用運算符「+」和「+=」添加方法,也可使用「-」和「-=」從委託中刪除方法調用。

所以咱們能夠在Main函數中經過「+」和「—「來進行委託的注入和去除。

static void Main(string[] args)

{

var signObj = new DeletegateDemo();

var mySignDelegateOne = new GetMySignDeletegate(signObj.GetStatus);

var mySignDelegateTwo = new GetMySignDeletegate(DeletegateDemo.GetSimpleSign);

GetMySignDeletegate myDeletegate = null;

myDeletegate += mySignDelegateOne;

myDeletegate += mySignDelegateTwo;

myDeletegate(4);

}

運行結果爲:

三.反射

(1)定義

Reflection,中文翻譯爲反射。這是.Net中獲取運行時類型信息的方式,.Net的應用程序由幾個部分:‘程序集(Assembly)’、‘模塊(Module)’、‘類型(class)’組成,而反射提供一種編程的方式,讓程序員能夠在程序運行期得到這幾個組成部分的相關信息,例如:

Assembly類能夠得到正在運行的裝配件信息,也能夠動態的加載裝配件,以及在裝配件中查找類型信息,並建立該類型的實例。

Type類能夠得到對象的類型信息,此信息包含對象的全部要素:方法、構造器、屬性等等,經過Type類能夠獲得這些要素的信息,而且調用之。

MethodInfo包含方法的信息,經過這個類能夠獲得方法的名稱、參數、返回值等,而且能夠調用之。

諸如此類,還有FieldInfo、EventInfo等等,這些類都包含在System.Reflection命名空間下。

(2)實現Demo

【1】Type類於獲取類型信息

定義class,咱們能夠在Main函數中獲取定義類型的相關信息:

static void Main(string[] args)

{

var reflctionObject=new MyReflection();

var type = reflctionObject.GetType();

Console.WriteLine("類型名:" + type.Name);

Console.WriteLine("類全名:" + type.FullName);

Console.WriteLine("命名空間名:" + type.Namespace);

Console.WriteLine("程序集名:" + type.Assembly);

Console.WriteLine("模塊名:" + type.Module);

Console.WriteLine("基類名:" + type.BaseType);

Console.WriteLine("是否類:" + type.IsClass);

Console.WriteLine("類的公共成員:");

var memberInfos = type.GetMembers();//獲得全部公共成員

foreach (var item in memberInfos)

{

Console.WriteLine("{0}:{1}", item.MemberType, item);

}

Console.ReadKey();

}

//定義class

public class  MyReflection

{

public string m = null;

public string Name { get; set; }

public void ShowMessage()

{

Console.WriteLine("My name is liupeng!");

}

}

運行結果:

 

【2】 獲取程序集元數據

static void Main(string[] args)

{

//獲取當前執行代碼的程序集

Assembly assem = Assembly.GetExecutingAssembly();

Console.WriteLine("程序集全名:"+assem.FullName);

Console.WriteLine("程序集的版本:"+assem.GetName().Version);

Console.WriteLine("程序集初始位置:"+assem.CodeBase);

Console.WriteLine("程序集位置:"+assem.Location);

Console.WriteLine("程序集入口:"+assem.EntryPoint);

Type[] types = assem.GetTypes();

Console.WriteLine("程序集下包含的類型:");

foreach (var item in types)

{

Console.WriteLine("類:"+item.Name);

}

}

運行結果:

【3】 動態加載類型

早綁定是在編譯時綁定對象類型,而晚綁定是在運行時才綁定對象的類型。利用反射能夠實現晚綁定,即動態加載類型,並調用他們的方法

static void Main(string[] args)

{

//動態建立類型

//獲取當前執行代碼的程序集

Assembly assem = Assembly.GetExecutingAssembly();

Console.WriteLine("Assembly Full Name:");

Console.WriteLine(assem.FullName);

// The AssemblyName type can be used to parse the full name.

AssemblyName assemName = assem.GetName();

Console.WriteLine("\\\\nName: {0}", assemName.Name);

Console.WriteLine("Version: {0}.{1}",

assemName.Version.Major, assemName.Version.Minor);

Console.WriteLine("\\\\nAssembly CodeBase:");

Console.WriteLine(assem.CodeBase);

// 從程序集中建立一個Example實例而且用object類型的引用o指向它,同時調用一個輸入參數的構造函數

Object o = assem.CreateInstance("Reflection.Example", false,

BindingFlags.ExactBinding,

null, new Object[] { 2 }, null, null);

//構造Example類的一個晚綁定的方法SampleMethod

MethodInfo m = assem.GetType("Reflection.Example").GetMethod("SampleMethod");

//調用剛纔實例化好的Example對象o中的SampleMethod方法,傳入的參數爲42

Object ret = m.Invoke(o, new Object[] { 42 });

Console.WriteLine("SampleMethod returned {0}.", ret);

Console.WriteLine("\\\\nAssembly entry point:");

Console.WriteLine(assem.EntryPoint);

Console.ReadKey();

}

public class Example

{

private int factor;

public Example(int f)

{

factor = f;

}

public int SampleMethod(int x)

{

Console.WriteLine("\\\\nExample.SampleMethod({0}) executes.", x);

return x * factor;

}

}

運行結果爲:

 

四.反射的運用

(1)使用反射經過讀取配置文件來動態的建立相關類的對象

//主函數

public static void Main()

{

#region 同程序集下

System.Type type = System.Type.GetType(ConfigurationManager.AppSettings["LogType"].ToString());

ILog log = (ILog)Activator.CreateInstance(type);

log.Write(new Exception("異常測試"));

#endregion

#region 不一樣程序集

string assemblyPath = Path.Combine(Environment.CurrentDirectory, "LogClassLibrary.dll");

Assembly a = Assembly.LoadFrom(assemblyPath);

Type type = a.GetType(ConfigurationManager.AppSettings["LogType"].ToString());

LogClassLibrary.ILog log = (LogClassLibrary.ILog)type.InvokeMember(null,BindingFlags.CreateInstance,null,null,null);

log.Write(new Exception("異常測試"));

#endregion

}

//app.config

//方法實現

public class TextFileLog : ILog

{

public bool Write(string message)

{

string fileDir = ConfigurationManager.AppSettings["LogTarget"].ToString();

using (StreamWriter w = File.AppendText(fileDir))

{

// w.Write(" Log Entry : ");

w.WriteLine("發生時間{0}", DateTime.Now.ToLocalTime().ToString());

w.WriteLine("日誌內容爲:{0}", message);

w.WriteLine("-------------------------------");

// Update the underlying file.

w.Flush();

w.Close();

}

return true;

}

public bool Write(Exception ex)

{

Write(ex.Message);

return true;

}

}

運行之後在C盤目錄下,能夠看到日誌記錄:

(2)插件編程技術

插件是指遵循必定的接口規範、能夠動態加載和運行的程序模塊。從上面的例子能夠看出,經過反射能夠很是方便的動態加載程序集。所以,利用反射的動態加載代碼能力,能夠很容易的實現插件。

插件編程的要點是使用接口來定義插件的功能特徵。插件的宿主程序經過接口來確認、裝載和執行插件的功能,實現插件功能的全部類都必須實現定義插件的接口。

【1】宿主加載插件

public class Host : IHost    {      

 private Listplugins = new List();      

#region IHost 成員        

public ListPlugins

{

get { return plugins; }

}

public int LoadPlugins(string path)

{

string[] assemblyFiles = Directory.GetFiles(path, "*.dll");

foreach (var file in assemblyFiles)

{

Assembly assembly = Assembly.LoadFrom(file);

foreach (var type in assembly.GetExportedTypes())

{

if (type.IsClass && typeof(ILog).IsAssignableFrom(type))

{

ILog plugin = Activator.CreateInstance(type) as ILog;

plugins.Add(plugin);

}

}

}

return plugins.Count;

}

public ILog GetLog(string name)

{

foreach (var item in plugins)

{

if (item.GetType().ToString()==name)

{

return item;

}

}

return null;

}

#endregion

【2】接口定義    public interface IHost    {        ListPlugins { get; }

int LoadPlugins(string path);

ILog GetLog(string name);

}

【3】主函數調用

static void Main(string[] args)

{

Host.Host host = new Host.Host();

host.LoadPlugins(".");

InterfaceLayer.ILog log = host.GetLog(ConfigurationManager.AppSettings["LogType"].ToString());

log.Write(new Exception("異常測試"));

}

相關文章
相關標籤/搜索