美文网首页asp.net程序员
C#基础回顾(三)—索引器、委托、反射

C#基础回顾(三)—索引器、委托、反射

作者: 8fdc8496dceb | 来源:发表于2016-01-16 12:49 被阅读164次

    一.前言

    人生路蜿蜒曲折,独自闯荡

    二.索引器

    (1)定义:

    索引器是一种特殊的类成员,它能够让对象以类似数组的形式来存取,使程序看起来更为直观,更容易编写。

    定义形式如下:

    [修饰符] 数据类型 this[索引类型 index]

    {

    get{//获得属性的代码}

    set{//设置属性的代码}

    }

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

    (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盘目录下,可以看到日志记录:

    re

    (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("异常测试"));

    }

    相关文章

      网友评论

      • 曾樑:代码可以用Markdown的专用格式哦
        8fdc8496dceb:@曾樑 谢谢,下次注意了!:smile:

      本文标题:C#基础回顾(三)—索引器、委托、反射

      本文链接:https://www.haomeiwen.com/subject/qbdhkttx.html