最近在用orchard这个开源的cms系统给公司做官网,深刻的领略到了动态类型的强大,在这里主要想讲一下dynamic以及ExpandoObject和DynamicObject的简单使用。由于dynamic是动态类型,所以我们可以动态的给它扩展属性和方法。动态类型如此的强大,但也不是没有缺点。由于编译器会忽略对该类型的类型检查,只有在运行时才会对它进行解析,因此我们在使用的时候就必须特别小心,以免在运行时发生不可知的错误,而且动态类型在使用的时候也没有智能感知。
一、ExpandoObject的使用
下面我们就从实际的例子开始讲解:
1、创建一个控制台应用程序,输入名称ExpandoObjectDemo,点击确定
2、由于代码比较简单,所以下面直接给出源码供大家参考
class Program { static void Main(string[] args) { dynamic expando = new ExpandoObject(); expando.Name = "FlyDream"; expando.Show = new Action(() => { Console.WriteLine("我是{0}", expando.Name); }); expando.Show(); Console.ReadKey(); } }
3、运行结果
我是FlyDream
4、结论
通过dynamic关键字和ExpandoObject类型,我们可以很方便的为动态类型扩展属性和方法。
二、DynamicObject的使用
通过继承自DynamicObject类型,并重写该类内的虚方法,可以为我们提供运行时的动态功能,下面从一个实际的项目来详细的讲解下。
1、创建一个控制台应用程序,输入名称DynamicObjectDemo,点击确定
2、首先新建一个枚举类StringSearchOption,这个枚举主要用来标示检索符串的方式,代码如下
public enum StringSearchOption { StartsWith, Contains, EndsWith }
3、新建类 ReadFromFile ,让该类继承自DynamicObject,定义一个私有字段用来存储文件的路径和一个带参构造函数
private readonly string _filePath; public ReadFromFile( string filePath) { if (!File.Exists(filePath)) { throw new Exception("文件路径不存在!"); } _filePath = filePath; }
4、给该类添加一个方法,该方法会通过指定的字符串和检索模式进行按行查找,如果匹配到的话就将该行存储在集合中,最后返回该该集合
public List<string> GetTextValue(string textName, StringSearchOption opt = StringSearchOption.StartsWith, bool trimSpaces = true) { StreamReader sr = null; List<string> results = new List<string>(); string line = string.Empty; string upperLine = string.Empty; using (sr=new StreamReader(_filePath)) { try { while(!sr.EndOfStream) { line = sr.ReadLine(); upperLine = line.ToUpper(); if(trimSpaces) { upperLine = upperLine.Trim(); } switch (opt) { case StringSearchOption.StartsWith: if (upperLine.StartsWith(textName.ToUpper())) { results.Add(line); } break; case StringSearchOption.Contains: if (upperLine.Contains(textName.ToUpper())) { results.Add(line); } break; case StringSearchOption.EndsWith: if (upperLine.EndsWith(textName.ToUpper())) { results.Add(line); } break; } } } catch { results = null; } } return results; }
5、接下来我们重写基类DynamicObject的TryGetMemeber方法,这个方法会在我们调用动态类型的属性的时候被执行,其中binder.Name的值是动态类型的属性名,如果有值我们返回true,否则返回false。
public override bool TryGetMember(GetMemberBinder binder, out object result) { result = GetTextValue(binder.Name); return result == null ? false : true; }
6、接下来我们重写基类DynamicObject的TryInvokeMember方法,这个方法会在我们调用动态类型的方法的时候被执行,其中binder.Name的值是动态类型的方法名,args参数的值是动态类型方法的参数值,最后如果有值我们返回true,否则返回false。
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) { var opt = StringSearchOption.StartsWith; bool trimSpaces = true; try { if(args.Length>0) { opt = (StringSearchOption)args[0]; } } catch { throw new ArgumentException("opt参数必须是StringSearchOption的枚举值"); } try { if (args.Length>1) { trimSpaces = (bool)args[1]; } } catch { throw new ArgumentException("trimSapces参数必须是布尔值"); } result = GetTextValue(binder.Name, opt, trimSpaces); return result == null ? false : true; }
7、创建一个文本文件,输入名称TextDemo,并确定,然后输入以下内容
List of customers and suppliers Supplier: Hans Customer: Lucy Customer: Lily Supplier: Maria
8、最后在Main方法中写下测试代码,如下所示
static void Main(string[] args) { dynamic file = new ReadFromFile(@"..\..\TextDemo.txt"); foreach (string line in file.Customer) { Console.WriteLine(line); } Console.WriteLine("-------------------"); foreach (string line in file.Customer(StringSearchOption.Contains,true)) { Console.WriteLine(line); } Console.ReadLine(); }
9、执行结果
Customer: Lucy
Customer: Lily
-------------------
List of customers and suppliers
Customer: Lucy
Customer: Lily