zoukankan      html  css  js  c++  java
  • Effective C# 学习笔记(四十四)合理地在C#中使用Dynamic特性

    尽管C# 4.0中添加了 Dynamic特性,但是本质上说C#还是一个静态语言。而过多的使用动态特性会是你的程序难于维护,易于出错,所以我们要讲一个“度”字。

    原则是:在必须使用Dynamic的时候使用之,但将使用Dynamic的逻辑的地方用静态类型的方式封装起来供外界调用。(如使用范型转换Dynamic类型)

     

    如在《Effective C# 学习笔记(三十八)理解Dynamic的得与失》中我们说过的关于Dynamic的代码,其动态逻辑产生的代码是冗长的,而且在每次动态调用时都会动态生成,效率不高,如下代码所示:

    dynamic answer = Add(5, 5);

    Console.WriteLine(answer);

     

    //其对应生成的C#代码如下:

    // Compiler generated, not legal user C# code

    object answer = Add(5, 5);

    if (<Main>o__SiteContainer0.<>p__Site1 == null)

    {

    <Main>o__SiteContainer0.<>p__Site1 = CallSite<Action<CallSite, Type, object>>.Create(

    new CSharpInvokeMemberBinder( CSharpCallFlags.None, "WriteLine",

    typeof(Program), null, new CSharpArgumentInfo[]

    {

    new CSharpArgumentInfo(

    CSharpArgumentInfoFlags.IsStaticType |

    CSharpArgumentInfoFlags.UseCompileTimeType, null),

    new CSharpArgumentInfo(

    CSharpArgumentInfoFlags.None, null)

    }));

    }

    <Main>o__SiteContainer0.<>p__Site1.Target.Invoke(<Main>o__SiteContainer0.<>p__Site1,

    typeof(Console), answer);

     

    我们可以这样来封装内部动态逻辑,而在外部只暴露静态逻辑。如下代码所示:

     

    //私有动态加法逻辑

    private static dynamic DynamicAdd(dynamic left, dynamic right)

    {

    return left + right;

    }

     

    // Wrap it:

    public static T1 Add<T1, T2>(T1 left, T2 right)

    {

    //封装动态逻辑,返回由范型转换的动态类型对象

    dynamic result = DynamicAdd(left, right);

    return (T1)result;

    }

     

    上面的代码保证了动态逻辑的封装,对外只返回了静态类型的对象,而对于动态代码的生成也只会在静态方法Add中生成一次,既灵活地处理了动态的逻辑,又提高了效率,可谓一举两得。

     

    而对于加法操作数和返回值类型都不同的方法,其可重载为以下代码:

    public static TResult Add<T1, T2, TResult> (T1 left, T2 right)

    {

    dynamic result = DynamicAdd(left, right);

    return (TResult)result;

    }

     

    // Type arguments needed because

    // args are not the same type

    answer2 = Add<int, double, double>(5, 12.3);

    Console.WriteLine(answer);

     

    再举一例,读取CSV文件中的数据。由于读取的每个CSV中的列不尽相同,所以需要考虑用Dynamic来实现其读取逻辑,代码如下:

     public class CSVDataContainer

        {

         //CSV动态行类型

            private class CSVRow : DynamicObject

            {

     //以二元组集合定义行对象

                private List<Tuple<string, string>> values = new List<Tuple<string, string>>();

     

    //构建行的方法

                public CSVRow(IEnumerable<string> headers, IEnumerable<string> items)

                {

                    values.AddRange(headers.Zip(items, (header, value) => Tuple.Create(header, value)));

                }

     

    //动态获取对应列的值得方法

                public override bool TryGetMember(GetMemberBinder binder, out object result)

                {

                    var answer = values.FirstOrDefault(n => n.Item1 == binder.Name);

                    result = answer.Item2;

                    return result != null;

                }

            }

    //列集合

            private List<string> columnNames = new List<string>();

    //行集合

            private List<CSVRow> data = new List<CSVRow>();

     

    //从流中读取CSV数据,并构建列和行

            public CSVDataContainer(System.IO.TextReader stream)

            {           

       using (stream)

                {

                    var headers = stream.ReadLine();

                    columnNames = (from header in headers.Split(',')

                                   select header.Trim()).ToList();

                    var line = stream.ReadLine();

                    while (line != null)

                    {

                        var items = line.Split(',');

                        data.Add(new CSVRow(columnNames, items));

                        line = stream.ReadLine();

                    }

                }

            }

    //构建索引器

            public dynamic this[int index]

            {

                get { return data[index]; }

            }

    //返回枚举行对象

            public IEnumerable<dynamic> Rows

            {

                get { return data; }

            }

        }

     

    //使用方法

    StreamReader sr = new StreamReader(@"文件路径");

    CSVDataContainer csvDataContainer = new CSVDataContainer(sr);

    var rows = csvDataContainer.Rows;

    foreach (var item in rows)

    {

         Console.WriteLine("{0}: {1}", item.Name, item.Company);

    }

  • 相关阅读:
    浏览器默认样式
    display
    JS中的!=、== 、!==、===的用法和区别。
    getElementsByName
    让DIV的滚动条自动滚动到最底部
    uoj118 【UR #8】赴京赶考
    [MtOI2019]幽灵乐团
    uoj213 【UNR #1】争夺圣杯
    loj6198 谢特
    [CTSC2017]密钥
  • 原文地址:https://www.cnblogs.com/haokaibo/p/2128985.html
Copyright © 2011-2022 走看看