C#基础回顾(三)—索引器、委托、反射
一.前言
二.索引器
(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盘目录下,可以看到日志记录:
(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("异常测试"));
}
C#基础回顾(三)—索引器、委托、反射的更多相关文章
- .NET基础知识之七——索引器
索引器是什么?有什么作用?索引器允许类的实例以访问数组的形式来访问对象里面的属性.如我们经常可以看到类似于dr["name"]="test",或者 ...
- java基础回顾(三)——HashMap与HashTable
public class Hashtable extends Dictionary implements Map, Cloneable, java.io.Serializable public cla ...
- 《Inside C#》笔记(六) 属性、数组、索引器
一 属性 a) 属性可用于隐藏类的内部成员,对外提供可控的存取接口.属性相当于有些语言的getter.setter方法,只是使用起来更加方便一点,而且查看对应的IL码可以看到,属性的本质也确实是方法. ...
- 第一篇 .NET高级技术之索引器
基础知识补充 索引 器 没有名字 ,索引器的内部本质 (ILSpy的IL模式下看)类型 this[参数]{get;set;} 可以是只读或者只写(在get或者set前加上private) 字符串是只读 ...
- Javascript基础回顾 之(三) 面向对象
本来是要继续由浅入深表达式系列最后一篇的,但是最近团队突然就忙起来了,从来没有过的忙!不过喜欢表达式的朋友请放心,已经在写了:) 在工作当中发现大家对Javascript的一些基本原理普遍存在这里或者 ...
- C#基础加强(1)之索引器
索引器 介绍 索引器,初学者可能听起来有些陌生,但其实我们经常会用到它,例如: // 字符串的索引器 string str = "hello world"; ]; // 获取到字符 ...
- C# 基础之索引器
当一个类有数组成员时,索引器将大大简化对类中数组成员的访问 索引器类似于属性有get与set访问器 列如: 使用: 总结:从以上代码可以看出索引器也是对私有字段进行访问的方式,但此时的私有字段是数组类 ...
- C#基础--索引器
classProgram { staticvoidMain(string[] args) { man mm =new man(); mm[0]="jingya"; mm[1]=&q ...
- 【Unity|C#】基础篇(7)——属性(Property)/ 索引器(Indexer)
[学习资料] <C#图解教程>(第6章):https://www.cnblogs.com/moonache/p/7687551.html 电子书下载:https://pan.baidu.c ...
随机推荐
- 学习AOP之深入一点Spring Aop
上一篇<学习AOP之认识一下SpringAOP>中大体的了解了代理.动态代理及SpringAop的知识.因为写的篇幅长了点所以还是再写一篇吧.接下来开始深入一点Spring aop的一些实 ...
- 说说Golang的使用心得
13年上半年接触了Golang,对Golang十分喜爱.现在是2015年,离春节还有几天,从开始学习到现在的一年半时间里,前前后后也用Golang写了些代码,其中包括业余时间的,也有产品项目中的.一直 ...
- 引人瞩目的 CSS 变量(CSS Variable)
这是一个令人激动的革新. CSS 变量,顾名思义,也就是由网页的作者或用户定义的实体,用来指定文档中的特定变量. 更准确的说法,应该称之为 CSS 自定义属性 ,不过下文为了好理解都称之为 CSS 变 ...
- [原] KVM 虚拟化原理探究(3)— CPU 虚拟化
KVM 虚拟化原理探究(3)- CPU 虚拟化 标签(空格分隔): KVM [TOC] CPU 虚拟化简介 上一篇文章笼统的介绍了一个虚拟机的诞生过程,从demo中也可以看到,运行一个虚拟机再也不需要 ...
- 常用 meta 整理
<!-- 针对手持设备优化,主要是针对一些老的不识别viewport的浏览器,比如黑莓 --> <meta name="HandheldFriendly" con ...
- CentOS 6.5安装Node.js, npm
CentOS上可以通过下载*.tar.gz安装包的方式自己解压缩.编译的方式安装,同时还可以采用EPEL的方式安装: Node.js and npm are available from the Fe ...
- 微信小程序新单位rpx与自适应布局
rpx是微信小程序新推出的一个单位,按官方的定义,rpx可以根据屏幕宽度进行自适应,在rpx出现之前,web页面的自适应布局已经有了多种解决方案,为什么微信还捣鼓出新的rpx单位?在解释这个单位前,我 ...
- 聊聊从web session的共享到可扩展缓存设计
先从web session的共享说起 许多系统需要提供7*24小时服务,这类系统肯定需要考虑灾备问题,单台服务器如果宕机可能无法立马恢复使用,这必定影响到服务.这个问题对于系统规模来说,从小到大可 ...
- 【腾讯Bugly干货分享】Android进程保活招式大全
本文来自于腾讯bugly开发者社区,非经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/57ac4a0ea374c75371c08ce8 作者:腾讯——张兴华 目前市面上 ...
- DBCP 配置备注
<property name="initialSize" value="5"></property> <property name ...