最近在用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