说说表明式树,表明式树
分类:计算机编程

C# 知识回想 - 表达式树 Expression Trees

 

[C#] 说说表明式树,

表达式树(Expression Trees)

2018-01-08 19:00 by 沉睡的木木夕, 69 阅读, 1 批评, 收藏, 编辑

目录

  • 简介
  • 拉姆da 表明式创设表达式树
  • API 创造表明式树
  • 拆解解析表达式树
  • 发挥式树的长久性
  • 编写翻译表明式树
  • 推行表明式树
  • 改进表明式树
  • 调试

 

说说表达式树 - Expression Trees

[翻译]表达式树(Expression Trees)

*原作地址:

表明式树展现的是代码的树形构造,每三个节点都以叁个表达式,举个例子:调用三个艺术或者调用三个二元运算表明式比如 x < y

你能够透过表明式树来编写翻译和周转代码。那代表能动态修正运转的代码,就好比在数据库中运转LINQ以一个变量的样式查询数据和创设二个动态的查询语句。关于表明式树在LINQ的更Dolly用音信详见How to: Use Expression Trees to Build Dynamic Queries (C#).

表明式树也被用于DL奥迪Q7(动态语言运转时),提供DLTiguan与.NET Framework之间的互操作性,使编写翻译器分析(Emit卡塔尔(英语:State of Qatar)表达式树,并不是MSIL。关于DLSportage越多信息详细详见Dynamic Language Runtime Overview.

你能够用C#/VB编写翻译器在您的lambda表达式变量的底工上生成三个表达式树,或许您能够由此选拔在System.Linq.Expressions命名空间创设表明式树.

简介

  表明式树以树形数据构造表示代码,此中每八个节点都以少年老成种表明式,举个例子方法调用和 x < y 那样的二元运算等。

  你能够对表达式树中的代码实行编写制定和运算。那样能够动态改过可进行代码、在区别数据库中实行LINQ 查询以至开创动态查询。 

  表达式树仍为能够用来动态语言运营时 (DLPRADO卡塔尔(قطر‎以提供动态语言和 .NET Framework 之间的互操作性。 

 

  轻巧说下宣布式树。

 

从Lambda表达式成立表明式树

当四个lambda表达式被分配到品种为Expression的的一个变量时,编写翻译器会解析生成代码创设三个表明式树来代表这么些lambda .

C#编写翻译器能从lambda生成表达式树(或许从二个单行的lambda)。但它不可能转换来lambda注解(或多行lambda)。越来越多关于lambda消息见Lambda Expressions.

下边包车型大巴代码例子表明了什么样用C#来生成一个表明式树来代表一个lambda表明式: num => num < 5

Expression<Func<int, bool>> lambda = num => num < 5;

生龙活虎、Lambda 表明式成立表明式树

  若 lambda 表明式被分配给 Expression<TDelegate> 类型的变量,则编写翻译器可以发射代码以创造表示该 lambda 表明式的发挥式树。  

  C# 编写翻译器只好从表达式 lambda (或单行 lambda)生成表达式树。 

  下列代码示例使用主要字 Expression成立表示 lambda 表明式:

1             Expression<Action<int>> actionExpression = n => Console.WriteLine(n);
2             Expression<Func<int, bool>> funcExpression1 = (n) => n < 0;
3             Expression<Func<int, int, bool>> funcExpression2 = (n, m) => n - m == 0;

 

目录

 

由此API创制表明式树

应用微软提供的API——Expression这一个类来创建表明式树。这几个类满含了成立钦命项目表明式树节点的静态工厂方法,举例, ParameterExpression它表示三个参数可能变量,又如MethodCallExpression,它意味着二个格局调用。ParameterExpression, MethodCallExpression以至别的的钦赐项目标表达式树都在System.Linq.Expressions命名空间下。这个类都一而再三番五次自 Expression抽象类.

上面包车型地铁代码展现什么用API成立表达式树来表示三个lambda表达式num => num < 5

// 在你的代码文件添加引用:  
// using System.Linq.Expressions;  

// 为lambda表达式num => num < 5手动生成表达式树   
ParameterExpression numParam = Expression.Parameter(typeof(int), "num");  
ConstantExpression five = Expression.Constant(5, typeof(int));  
BinaryExpression numLessThanFive = Expression.LessThan(numParam, five);  
Expression<Func<int, bool>> lambda1 =  
    Expression.Lambda<Func<int, bool>>(  
        numLessThanFive,  
        new ParameterExpression[] { numParam }); 

在.NET Framework4.0随后,表明式树API也协理分配和决定流表明式,举例循环,条件推断块乃相当度捕捉块(try-catch卡塔尔(英语:State of Qatar)。通过API,你能够创建比编写翻译器通过从lambda表明式创造的更加的复杂的发挥式树。下边包车型地铁那么些事例显示了什么创制一个表明式树来代表一个数的阶乘(factorial of number卡塔尔(英语:State of Qatar).

//创建一个参数表达式
ParameterExpression value = Expression.Parameter(typeof(int), "value");
//创建一个表达式表示本地变量
ParameterExpression result = Expression.Parameter(typeof(int), "result");
//创建标签从循环跳到指定标签
LabelTarget label = Expression.Label(typeof(int));
//创建方法体
BlockExpression block = Expression.Block(
    //添加本地变量
    new[] { result },
    //为本地变量赋值一个常量
    Expression.Assign(result, Expression.Constant(1)),
    //循环
    Expression.Loop(
        //添加循环条件
        Expression.IfThenElse(
            //条件:value > 1
            Expression.GreaterThan(value, Expression.Constant(1)),
            //if true
            Expression.MultiplyAssign(result, Expression.PostDecrementAssign(value)),
            //if false
            Expression.Break(label, result)
            ),
        label
        )
    );

int facotorial = Expression.Lambda<Func<int, int>>(block, value).Compile()(5);  
Console.WriteLine(factorial);  
// 输出 120.  

越来越多关于详见Generating Dynamic Methods with Expression Trees in Visual Studio 2010,也支撑后续VS版本.

二、API 制造表明式树

  通过 API 成立表明式树须要使用 Expression 类

  下列代码示例显示怎么样通过 API 创设表示 lambda 表明式:num => num == 0

1             //通过 Expression 类创建表达式树
2             //  lambda:num => num == 0
3             ParameterExpression pExpression = Expression.Parameter(typeof(int));    //参数:num
4             ConstantExpression cExpression = Expression.Constant(0);    //常量:0
5             BinaryExpression bExpression = Expression.MakeBinary(ExpressionType.Equal, pExpression, cExpression);   //表达式:num == 0
6             Expression<Func<int, bool>> lambda = Expression.Lambda<Func<int, bool>>(bExpression, pExpression);  //lambda 表达式:num => num == 0

  代码应用 Expression 类的静态方法实行创办。

 

介绍

  表达式树以树形数据布局表示代码,在那之中每一个节点都是豆蔻梢头种表明式,比如方法调用和 x < y 那样的二元运算等。

  你能够对表达式树中的代码举办编写制定和平运动算。那样能够动态纠正可进行代码、在不相同数据库中实行LINQ 查询以至开创动态查询。 

  表达式树仍可以够用于动态语言运转时 (DLSportage卡塔尔国 以提供动态语言和 .NET Framework 之间的互操作性,同期保障编写翻译器编写员能够发射表明式树而非 Microsoft 中间语言 (MSIL卡塔尔。 

 

浅析表明式树(Parsing Expression Trees卡塔尔(英语:State of Qatar)

下边包车型地铁代码示例演示了如何将表明式树表示为lambda表明式num => num < 5,能够被解释为一些。

public void DecomposedExpressionTrees()
{
    //创建一个表达式树
    Expression<Func<int, bool>> exprTree = num => num < 5;
    //分解表达式
    ParameterExpression param = (ParameterExpression)exprTree.Parameters[0];
    //num < 5
    BinaryExpression operation = (BinaryExpression)exprTree.Body;
    ParameterExpression left = (ParameterExpression)operation.Left;
    ConstantExpression right = (ConstantExpression)operation.Right;

    Console.WriteLine("Decomposed expression: {0} => {1} {2} {3}",
            param.Name, left.Name, operation.NodeType, right.Value);
}

三、深入深入分析表明式树 

   下列代码示例映现怎样分利肠府示 lambda 表达式 num => num == 0 的表述式树。

1             Expression<Func<int, bool>> funcExpression = num => num == 0;
2 
3             //开始解析
4             ParameterExpression pExpression = funcExpression.Parameters[0]; //lambda 表达式参数
5             BinaryExpression body = (BinaryExpression)funcExpression.Body;  //lambda 表达式主体:num == 0
6 
7             Console.WriteLine($"解析:{pExpression.Name} => {body.Left} {body.NodeType} {body.Right}");

图片 1

 

 

 

生龙活虎、依据 Lambda 表达式成立表明式树

  若 lambda 表明式被分配给 Expression<TDelegate> 类型的变量,则编写翻译器可以发射代码以创办表示该 lambda 表明式的发挥式树。  

  C# 编写翻译器只可以从表达式 lambda (或单行 lambda)生成表明式树。 

  下列代码示例使用首要字 Expression创设表示 lambda 表明式:

1             Expression<Action<int>> actionExpression = n => Console.WriteLine(n);
2             Expression<Func<int, bool>> funcExpression1 = (n) => n < 0;
3             Expression<Func<int, int, bool>> funcExpression2 = (n, m) => n - m == 0;

 

公布式树的不变性(Immutability of Expression Trees卡塔尔国

表明式树应该是不可变的。那象征风度翩翩旦您想改善表明式树,那么你必需另行已经存在的组织表明式树并替换其有个别节点。你能够接纳表明式树访问器(ExpressionVisitor)遍历表明式树。更加多那上边音讯详见How to: Modify Expression Trees (C#).

四、表明式树永远性

  表明式树应具备永远性(相像字符串)。那意味假设你想改进有些表达式树,则必得复制该表达式树然后替换此中的节点来创建二个新的揭橥式树。  你能够行使表明式树访谈者遍历现存表明式树。第七节介绍了怎么样改善表明式树。

 

二、通过 API 创立表明式树

  通过 API 成立表明式树须要利用 Expression 类

  下列代码示例彰显什么通过 API 创设表示 lambda 表明式:num => num == 0

1             //通过 Expression 类创建表达式树
2             //  lambda:num => num == 0
3             ParameterExpression pExpression = Expression.Parameter(typeof(int));    //参数:num
4             ConstantExpression cExpression = Expression.Constant(0);    //常量:0
5             BinaryExpression bExpression = Expression.MakeBinary(ExpressionType.Equal, pExpression, cExpression);   //二元表达式:num == 0
6             Expression<Func<int, bool>> lambda = Expression.Lambda<Func<int, bool>>(bExpression, pExpression);  //lambda 表达式:num => num == 0

  代码应用 Expression 类的静态方法进行创办。

 

编写翻译表达式树

泛型 Expression 类型提供三个 Compile主意来将表明式树所表示的代码编译成可实行的寄托。

下边这段代码彰显怎么编写翻译表明式树和平运动作结果代码

public void ComplieExpressTrees()
{
    //创建一个表达式树
    Expression<Func<int, bool>> expr = num => num < 5;
    //编译表达式树为委托
    Func<int, bool> result = expr.Compile();
    //调用委托并写结果到控制台
    Console.WriteLine(result(4));

    //也可以使用简单的语法来编译运行表达式树
    Console.WriteLine(expr.Compile()(4));
    //结果一样
}

更加多关于怎么着运维表明式树音讯,详见How to: Execute Expression Trees (C#).

愿意有个生活美好的次序人生

 

 

 

本节首要展现什么去实施表明式树。运维三个或然含有重临值或只是施行叁个操作,比方方法调用的表明式树。

除非表示lambda表达式的表明式树能够被施行。它是四个 LambdaExpression 或 Expression 类型。为了施行那么些表明式树,调用 Compile 方法来生成三个可进行的委托并调用它。

注意:

固然这几个委托的项目是不解的,那么那个委托的品种是LambdaExpression并不是Expression,你必需调用委托的 DynamicInvoke方法并不是平昔调用Invoke。

借使三个表达式树不表示叁个lambda表达式,你能够创设三个新的表明式树将原来的表明式树来作为它的Body,通过调用 Lambda(Expression, IEnumerable) 方法。然后你就可以调用那么些lambda表明式了

五、编译表达式树

  Expression<TDelegate> 类型提供了 Compile 方法以将表明式树表示的代码编写翻译成可执行委托。

1             //创建表达式树
2             Expression<Func<string, int>> funcExpression = msg => msg.Length;
3             //表达式树编译成委托
4             var lambda = funcExpression.Compile();
5             //调用委托
6             Console.WriteLine(lambda("Hello, World!"));
7 
8             //语法简化
9             Console.WriteLine(funcExpression.Compile()("Hello, World!"));

图片 2

 

 

 

 

 三、深入分析表明式树 

   下列代码示例显示如何讲明表示 lambda 表明式 num => num == 0 的发表式树。

1             Expression<Func<int, bool>> funcExpression = num => num == 0;
2 
3             //开始解析
4             ParameterExpression pExpression = funcExpression.Parameters[0]; //lambda 表达式参数
5             BinaryExpression body = (BinaryExpression)funcExpression.Body;  //lambda 表达式主体:num == 0
6 
7             Console.WriteLine($"解析:{pExpression.Name} => {body.Left} {body.NodeType} {body.Right}");

1 //创造表明式树 2 Expression<Func<string, int>> funcExpression = msg => msg.Length; 3 //表明式树编写翻译成委托 4 var lambda = funcExpression.Compile(卡塔尔(英语:State of Qatar); 5 //调用委托 6 Console.WriteLine(lambda("Hello, World!"卡塔尔卡塔尔国; 7 8 //语法简化 9 Console.WriteLine(funcExpression.Compile(卡塔尔(قطر‎("Hello, World!"));

1 const int n = 1; 2 const int m = 2; 3 4 //待试行的表达式树 5 BinaryExpression bExpression = Expression.Add(Expression.Constant(n卡塔尔(قطر‎, Expression.Constant(m卡塔尔卡塔尔; 6 //创设 lambda 表明式 7 Expression<Func<int>> funcExpression = Expression.Lambda<Func<int>>(bExpression卡塔尔(قطر‎; 8 //编写翻译 lambda 表达式 9 Func<int> func = funcExpression.Compile(卡塔尔(قطر‎; 10 11 //推行lambda 表明式 12 Console.WriteLine($"{n} {m} = {func(卡塔尔(英语:State of Qatar)}"卡塔尔(قطر‎;

图片 3

 

Example

下边包车型地铁代码表达什么运转叁个象征三个数的幂运算的表明式树通过生成lambda并调用它。结果是显得那一个数的平方

//执行表达式树
BinaryExpression be = Expression.Power(Expression.Constant(2D), Expression.Constant(3D));
//创建一个委托表达式
Expression<Func<double>> le = Expression.Lambda<Func<double>>(be);
// 编译lambda表达式
Func<double> compiledExpression = le.Compile();
//执行lambda表达式
double result = compiledExpression();
//显示值
Console.WriteLine(result);

六、试行表明式树

  实践表达式树恐怕会回去叁个值,也说倒霉仅施行贰个操作(比如调用方法)。

  只可以举行代表 lambda 表明式的表达式树。表示 lambda 表达式的表明式树归属 LambdaExpression 或 Expression<TDelegate> 类型。若要推行那个表明式树,必要调用 Compile 方法来创设二个可推行委托,然后调用该信托。

 1             const int n = 1;
 2             const int m = 2;
 3 
 4             //待执行的表达式树
 5             BinaryExpression bExpression = Expression.Add(Expression.Constant(n), Expression.Constant(m));
 6             //创建 lambda 表达式
 7             Expression<Func<int>> funcExpression = Expression.Lambda<Func<int>>(bExpression);
 8             //编译 lambda 表达式
 9             Func<int> func = funcExpression.Compile();
10 
11             //执行 lambda 表达式
12             Console.WriteLine($"{n}   {m} = {func()}");

图片 4

 

七、如何:改正表明式树 

   该类世袭 ExpressionVisitor 类,而且专用于改革意味着原则 AND 运算的表明式。它将那一个运算从原则 AND 校勘为基准 OR。为此,该类将重写基类型的 VisitBinary 方法,那是因为条件 AND 表明式代表为二元表明式。在 VisitBinary 方法中,即便传递到该方法的表明式表示原则AND 运算,代码将组织一个饱含条件 OR 运算符(并不是原则 AND 运算符)的新表达式。如若传递到 VisitBinary 的表明式不表示原则 AND运算,则该措施交由基类实现来拍卖。  基类方法协会相似于传播的表明式树的节点,但这几个节点将其子目录树替换为访问器递归生成的揭橥式树。  

 1     internal class Program
 2     {
 3         private static void Main(string[] args)
 4         {
 5             Expression<Func<int, bool>> funcExpression = num => num == 0;
 6             Console.WriteLine($"Source: {funcExpression}");
 7 
 8             var visitor = new NotEqualExpressionVisitor();
 9             var expression = visitor.Visit(funcExpression);
10 
11             Console.WriteLine($"Modify: {expression}");
12 
13             Console.Read();
14         }
15 
16         /// <summary>
17         /// 不等表达式树访问器
18         /// </summary>
19         public class NotEqualExpressionVisitor : ExpressionVisitor
20         {
21             public Expression Visit(BinaryExpression node)
22             {
23                 return VisitBinary(node);
24             }
25 
26             protected override Expression VisitBinary(BinaryExpression node)
27             {
28                 return node.NodeType == ExpressionType.Equal
29                     ? Expression.MakeBinary(ExpressionType.NotEqual, node.Left, node.Right) //重新弄个表达式:用 != 代替 ==
30                     : base.VisitBinary(node);
31             }
32         }
33     }

图片 5

 

 


【原来的小说链接】 

 

预览版,更新于09/16

 

  

] 说说表达式树, 说说表明式树 - Expression Trees 序 轻巧说下发挥式树。 目录 介绍 表明式树以树形数据布局表示代码,个中每三个节点都...

编写翻译的代码

  • 增多项目引用 System.Core.dll
  • 增加命名空间 System.Linq.Expressions

七、改善表明式树 

   该类世襲 ExpressionVisitor 类,通过 Visit 方法直接调用 VisitBinary 方法将 != 替换来==。基类方法组织相似于传播的发表式树的节点,但这几个节点将其子目录树替换为访谈器递归生成的表述式树。  

 1     internal class Program
 2     {
 3         private static void Main(string[] args)
 4         {
 5             Expression<Func<int, bool>> funcExpression = num => num == 0;
 6             Console.WriteLine($"Source: {funcExpression}");
 7 
 8             var visitor = new NotEqualExpressionVisitor();
 9             var expression = visitor.Visit(funcExpression);
10 
11             Console.WriteLine($"Modify: {expression}");
12 
13             Console.Read();
14         }
15 
16         /// <summary>
17         /// 不等表达式树访问器
18         /// </summary>
19         public class NotEqualExpressionVisitor : ExpressionVisitor
20         {
21             public Expression Visit(BinaryExpression node)
22             {
23                 return VisitBinary(node);
24             }
25 
26             protected override Expression VisitBinary(BinaryExpression node)
27             {
28                 return node.NodeType == ExpressionType.Equal
29                     ? Expression.MakeBinary(ExpressionType.NotEqual, node.Left, node.Right) //重新弄个表达式:用 != 代替 ==
30                     : base.VisitBinary(node);
31             }
32         }
33     }

图片 6

 

 

 

哪些纠正表明式树

那节首要体现怎么样去订正表明式树。表明式树是不可变的(Immutable),意味着它不可能被平昔更改。为了改过表明式树,那么您必得新建一个业已存在的表述式树的别本,并在创设别本时实行所需的改动。你能够使用 ExpressionVisitor 类去分析表达式树并复制它访问的每三个节点。

八、调试

  8.1 参数表明式

1             ParameterExpression pExpression1 = Expression.Parameter(typeof(string));
2             ParameterExpression pExpression2 = Expression.Parameter(typeof(string), "msg");

图片 7

图8-1

图片 8

图8-2

   从 DebugView 可以预知,假诺参数未有称谓,则会为其分配叁个自动生成的称号。

 

1             const int num1 = 250;
2             const float num2 = 250;
3 
4             ConstantExpression cExpression1 = Expression.Constant(num1);
5             ConstantExpression cExpression2 = Expression.Constant(num2);

图片 9

图8-3

图片 10

图8-4

   从 DebugView 可见,float 比 int 多了个后缀 F。

 

1             Expression lambda1 = Expression.Lambda<Func<int>>(Expression.Constant(250));
2             Expression lambda2 = Expression.Lambda<Func<int>>(Expression.Constant(250), "CustomName", null);

图片 11

图8-5

图片 12

图8-6

   阅览 DebugView ,假使 lambda 表明式没盛名称,则会为其分配三个自动生成的称谓。

 

修正表达式树

  1. 新建调整台应用程序

  2. 丰硕引用 System.Linq.Expressions

  3. 在您的门类中增添类 AndAlsoModifier

```c#
public class AndAlsoModifier : ExpressionVisitor
{
public Expression Modify(Expression expression)
{
return Visit(expression);
}

   protected override Expression VisitBinary(BinaryExpression b)
   {
       if(b.NodeType == ExpressionType.AndAlso)
       {
           Expression left = this.Visit(b.Left);
           Expression right = this.Visit(b.Right);

           //让二元运算符OrElse代替AndAlso
           return Expression.MakeBinary(ExpressionType.OrElse, left, right, b.IsLiftedToNull, b.Method);
       }
       return base.VisitBinary(b);
   }

}
```

其生机勃勃类世襲了 ExpressionVisitor 况且特意用来改良代表原则 And 操作的表明式。它改换从 And 条件到 OR。为了这些指标, AndAlsoModifier 重写了基类的 VisitBinary 方法,因为 And 表示的是多个二元表明式。在 VisitBinary 方法中,如若这些表明式传递的是 And 操作,代码会协会二个满含条件操作 OR 新的表明式并不是 And。假设表达式传给 VisitBinary 的不是 And 操作,那么方法就能够优先基类的贯彻。它基类的点子组织二个节点好似传递进入的表明式树相通,可是那一个节点有它们的子树,被报事人递归生成的表明式树替换。

  1. 加上援引 System.Linq.Expressions

  2. 在 Program.cs 文件增加 Main 方法并并创制四个表明式树传递给那一个法子来校正它。

```c#
Expression<func<string, bool="">> expr = name => name.Length > 10 && name.StartsWith("G");
Console.WriteLine(expr);

AndAlsoModifier treeModifier = new AndAlsoModifier();
Expression modifiedExpr = treeModifier.Modify((Expression) expr);

Console.WriteLine(modifiedExpr);

/* This code produces the following output:

   name => ((name.Length > 10) && name.StartsWith("G"))  
   name => ((name.Length > 10) || name.StartsWith("G"))  

*/
```

这段代码创制了三个蕴含 And 操作的抒发式树。然后新建二个 AndAlsoModifier 的实例并给艺术 Modify 传递从前成立的发表式树。并出口原始和校订后的表达式树展现差别。

  1. 编写翻译并运路程序。

期望有个生活能够的程序人生

 

表明式树(Expression Trees)

 

 

 

 


【原来的小说链接】 

【参谋】微软官方文书档案

 

 

本文由pc28.am发布于计算机编程,转载请注明出处:说说表明式树,表明式树

上一篇:net接口学习笔记 下一篇:没有了
猜你喜欢
热门排行
精彩图文
  • NET开拓能源大全
    NET开拓能源大全
    目录 API 应用框架(ApplicationFrameworks) 应用模板(ApplicationTemplates) 人工智能(ArtificialIntelligence) 程序集处理(AssemblyManipulation) 资源(Assets) 认证和授
  • STM32就学笔记之C语言篇
    STM32就学笔记之C语言篇
    【unsigned】 1、rewind(FILE *卡塔尔(英语:State of Qatar):回到文件开头处 2、fprintf(), fscanf(), fgets(), fputs() (1)、fprintf(#FILE *restrict#, #const char *restrict,...#卡塔尔(英语
  • python面向对象三大特征,面向对象
    python面向对象三大特征,面向对象
    面向对象-组合 风流罗曼蒂克、面向进度与面向对象的简要介绍 一、继承 大器晚成 什么是多态动态绑定(在这里起彼伏的背景下行使时,一时也称得上多
  • HttpRuntime的认知与抓好明白,异步HTTP乞请操作
    HttpRuntime的认知与抓好明白,异步HTTP乞请操作
    一、说明 上边最早介绍HttpRuntime的Web.config里的构造 1卡塔尔(英语:State of Qatar) 那些类 是本身 在安分守己项目中,优化驱除实际难题时,不参照第三方代码
  • 那些年【深入.NET平台和C#编程】
    那些年【深入.NET平台和C#编程】
    一、深入.NET框架 ArrayList (非泛型集合  using System.Collections;) public void Text1(){ ArrayList al = new ArrayList (); al.Add ("刘德化");       //添加元素 al.Add ("张学友