理解c#中的dynamic以及ExpandoObject和DynamicObject的使用

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

发表评论