C#(010):C# 4.0 新特性(.NET Framework 4.0 与 Visual Studio 2010 )(C # (010): new features of C # 4.0 (. Net framework 4.0 and visual studio 2010))

一、dynamic binding:动态绑定

在通过 dynamic 类型实现的操作中,该类型的作用是不在编译时类型检查,而是在运行时解析这些操作。dynamic 类型简化了对 COM API(例如
Office Automation API)、动态 API(例如 IronPython 库)和 HTML 文档对象模型 (DOM) 的访问。

1、简化反射

在3.0及之前,如果你不知道一个变量的类型,而要去调用它的一个方法,一般会用到反射:

object calc = GetCalculator();

Type calcType = calc.GetType();object res = calcType.InvokeMember("Add",BindingFlags.InvokeMethod, null,new object[] { 10, 20 });

int sum = Convert.ToInt32(res);

有了dynamic,就可以把上面代码简化为:

dynamic calc = GetCalculator();

int sum = calc.Add(10, 20);

2、dynamic可用在变量、字段、属性、方法参数和返回值等地方。

void Main()

{

    dynamic dynamic_ec = new ExampleClass();

    Console.WriteLine(dynamic_ec.exampleMethod(10));

}



class ExampleClass

{

    static dynamic field;// 动态字段

    dynamic prop { get; set; }//动态属性.

    public dynamic exampleMethod(dynamic d)// 动态返回类型和动态参数

    {

        dynamic local = "Local variable";   // 动态局部变量

        int two = 2;



        if (d is int)

        {

            return local;

        }

        else

        {

            return two;

        }

    }

}

3、dynamic用在变量的传递中注意事项

dynamic也可以用在变量的传递中,runtime会自动选择一个最匹配的重载方法。

调用含有明确类型参数和含有dynamic 类型的重载函数时,优先调用的是明确定义的类型。当没有匹配的类型的时候,才会调用含有dynamic类的重载函数。

static void Main(string[] args)

{

    int i1 = 3;

    f(i1);



    double i2 = 1;

    f(i2);

}



static public void f(dynamic d)

{

    Console.WriteLine("dynamic ");

    Console.WriteLine(d);

    Console.WriteLine(d.GetType().ToString());

}



static public void f(int i)

{

    Console.WriteLine("int ");

    Console.WriteLine(i);

    Console.WriteLine(i.GetType().ToString());

}

4、dynamic的实现是基于 IDynamicObject 接口和 DynamicObject 抽象类。

直接使用该类型,可以非常方便的插入属性, 方法。

dynamic person = new System.Dynamic.ExpandoObject();

person.id = 1;

person.title = "aa";

person.url = "bb.com";

person.co = "cc";

person.des = new Func<string>(() => person.title +person.url);

Console.Write(person.des());//结果aabb.com

其中动态方法、属性的调用都被转为了GetMember、Invoke等方法的调用。

public abstract class DynamicObject : IDynamicObject

{

    public virtual object GetMember(GetMemberBinder info);

    public virtual object SetMember(SetMemberBinder info, object value);

    public virtual object DeleteMember(DeleteMemberBinder info); public virtual object UnaryOperation(UnaryOperationBinder info);

    public virtual object BinaryOperation(BinaryOperationBinder info, object arg);

    public virtual object Convert(ConvertBinder info); public virtual object Invoke(InvokeBinder info, object[] args);

    public virtual object InvokeMember(InvokeMemberBinder info, object[] args);

    public virtual object CreateInstance(CreateInstanceBinder info, object[] args); public virtual object GetIndex(GetIndexBinder info, object[] indices);

    public virtual object SetIndex(SetIndexBinder info, object[] indices, object value);

    public virtual object DeleteIndex(DeleteIndexBinder info, object[] indices); public MetaObject IDynamicObject.GetMetaObject();

}

5、var和dynamic之间的区别

  • **声明的变量
    ** 关键字var是在C#3.0中引入的,声明的变量是静态类型的,变量的类型由编译器在编译时决定。
    关键字dynamic是在C#4.0中引入的,声明的变量是动态类型的,变量的类型由编译器在运行时决定。
  • **初始化
    ** 关键字var声明的变量应在声明时初始化,这样编译器就会根据初始化的值来决定变量的类型。如果变量未初始化,则抛出错误。
    关键字dynamic声明的变量在声明时不需要初始化此类型的变量,因为编译器在编译时不知道变量的类型。如果变量未初始化,也不会抛出错误。
  • **intelliSense的支持
    ** 关键字var支持visual studio中的intelliSense。关键字dynamic不支持visual
    studio中的intelliSense
  • **应用
    ** 关键字var不能用于属性或从函数返回值。它只能用作函数中的局部变量。
    关键字dynamic可以用于属性或从函数返回值。

6、用dynamic增强C#泛型表达力

除了以下运算符重载,对于普通的方法调用也是适用的。这种方法是一种动态duck
typing的泛型参数约束机制,依赖于运行时的方法查找,与模板编译时的检查不同,它需要使用者保证传入的对象符合相应要求。

static class Calculator

{

    public static T Add<T>(T t1, T t2)

    {

       dynamic d1 = t1;

        dynamic d2 = t2;

        return (T)(d1 + d2);

    }

}



public static void Main(string[] args)

{

    int i = Calculator.Add(1, 2);

    string s = Calculator.Add("abc", "def");

    Console.WriteLine(i + " " + s);

}

二、Named and optional arguments:命名参数和可选参数

1、带有可选参数方法的声明:

public StreamReader OpenTextFile(string path, 

Encoding encoding = null, bool detectEncoding = true, int bufferSize = 1024

);

2、命名参数必须放在最后:

OpenTextFile("foo.txt", Encoding.UTF8, 

bufferSize:

 4096);

3、命名参数顺序不限:

OpenTextFile(

bufferSize:

4096, 

path:

 "foo.txt", 

detectEncoding:

 false);

三、Generic co- and contravariance:泛型的协变和逆变

在C#中,下面的类型转换是非法的:

IList<string> strings = new List<string>();

IList<object> objects = strings;

因为你有可能会这样做,而编译器的静态检查无法查出错误:

objects[0] = 5;

string s = strings[0];

4.0中在声明generic的Interface及Delegate时可以加in及out关键字,如:

public interface IEnumerable<out T> : IEnumerable

{

   IEnumerator<T> GetEnumerator();

}


public interface IEnumerator<out T> : IEnumerator

{

   bool MoveNext();

   T Current { get; }

}



public interface IComparer<in T>

{

 public int Compare(T left, T right);

}
  • out关键字的意思是说IEnumerable中T只会被用在输出中,值不会被改变。这样将IEnumerable转为IEnumerable类型就是安全的。
  • in的意思正好相反,是说IComparer中的T只会被用在输入中,这样就可以将IComparer安全的转为IComparer类型。

前者被称为Co-Variance协变, 后者就是Contra-Variance逆变 。

.Net4.0中使用out/in声明的Interface:

System.Collections.Generic.IEnumerable<out T>

System.Collections.Generic.IEnumerator<out T>

System.Linq.IQueryable<out T>

System.Collections.Generic.IComparer<in T>

System.Collections.Generic.IEqualityComparer<in T>

System.IComparable<in T>

Delegate:

System.Func<in T, …, out R>

System.Action<in T, …>

System.Predicate<in T>

System.Comparison<in T>

System.EventHandler<in T>

四、Embedded interop types (“NoPIA”):开启嵌入类型信息,增加引用COM组件程序的中立性

在C#中在调用COM对象如office对象时,经常需要写一堆不必要的参数:

object fileName = "Test.docx";

object missing  = System.Reflection.Missing.Value;

doc.SaveAs(ref fileName,

ref missing, ref missing, ref missing,

ref missing, ref missing, ref missing,

ref missing, ref missing, ref missing,

ref missing, ref missing, ref missing,

ref missing, ref missing, ref missing);

4.0中就可以直接写成:

doc.SaveAs("Test.docx");

C#4.0对COM交互做了下面几方面的改进:

  • Automatic object -> dynamic mapping
  • Optional and named parameters
  • Indexed properties
  • Optional “ref” modifier
  • Interop type embedding (“No PIA”)

对第1点和第5点的简单解释如下:

在COM调用中,很多输入输出类型都是object,这样就必须知道返回对象的确切类型,强制转换后才可以调用相应的方法。在4.0中有了dynamic的支持,就可以在导入这些COM接口时将变量定义为dynamic而不是object,省掉了强制类型转换。

PIA(Primary Interop Assemblies)是根据COM API生成的.Net
Assembly,一般体积比较大。在4.0中运行时不需要PIA的存在,编译器会判断你的程序具体使用了哪一部分COM
API,只把这部分用PIA包装,直接加入到你自己程序的Assembly里面。

————————

一、dynamic binding:动态绑定

In the operations implemented by dynamic type, the function of this type is not to check the type at compile time, but to resolve these operations at run time. Dynamic types simplify the use of COM APIs, such as
Access to office automation API), dynamic API (such as ironpython Library), and HTML document object model (DOM).

1. Simplified reflection

In 3.0 and before, if you don’t know the type of a variable and want to call a method of it, you will generally use reflection:

object calc = GetCalculator();

Type calcType = calc.GetType();object res = calcType.InvokeMember("Add",BindingFlags.InvokeMethod, null,new object[] { 10, 20 });

int sum = Convert.ToInt32(res);

With dynamic, the above code can be simplified to:

dynamic calc = GetCalculator();

int sum = calc.Add(10, 20);

2. Dynamic can be used in variables, fields, properties, method parameters and return values.

void Main()

{

    dynamic dynamic_ec = new ExampleClass();

    Console.WriteLine(dynamic_ec.exampleMethod(10));

}



class ExampleClass

{

    static dynamic field;// 动态字段

    dynamic prop { get; set; }//动态属性.

    public dynamic exampleMethod(dynamic d)// 动态返回类型和动态参数

    {

        dynamic local = "Local variable";   // 动态局部变量

        int two = 2;



        if (d is int)

        {

            return local;

        }

        else

        {

            return two;

        }

    }

}

3. Precautions for using dynamic in variable transfer

Dynamic can also be used in the transfer of variables, and the runtime will automatically select the most matching overloaded method.

When calling overloaded functions with explicit type parameters and dynamic types, the explicitly defined types take precedence. When there is no matching type, the overloaded function with dynamic class will be called.

static void Main(string[] args)

{

    int i1 = 3;

    f(i1);



    double i2 = 1;

    f(i2);

}



static public void f(dynamic d)

{

    Console.WriteLine("dynamic ");

    Console.WriteLine(d);

    Console.WriteLine(d.GetType().ToString());

}



static public void f(int i)

{

    Console.WriteLine("int ");

    Console.WriteLine(i);

    Console.WriteLine(i.GetType().ToString());

}

4、dynamic的实现是基于 IDynamicObject 接口和 DynamicObject 抽象类。

This method is very convenient to insert attributes directly.

dynamic person = new System.Dynamic.ExpandoObject();

person.id = 1;

person.title = "aa";

person.url = "bb.com";

person.co = "cc";

person.des = new Func<string>(() => person.title +person.url);

Console.Write(person.des());//结果aabb.com

The calls of dynamic methods and properties are transferred to the calls of getmember, invoke and other methods.

public abstract class DynamicObject : IDynamicObject

{

    public virtual object GetMember(GetMemberBinder info);

    public virtual object SetMember(SetMemberBinder info, object value);

    public virtual object DeleteMember(DeleteMemberBinder info); public virtual object UnaryOperation(UnaryOperationBinder info);

    public virtual object BinaryOperation(BinaryOperationBinder info, object arg);

    public virtual object Convert(ConvertBinder info); public virtual object Invoke(InvokeBinder info, object[] args);

    public virtual object InvokeMember(InvokeMemberBinder info, object[] args);

    public virtual object CreateInstance(CreateInstanceBinder info, object[] args); public virtual object GetIndex(GetIndexBinder info, object[] indices);

    public virtual object SetIndex(SetIndexBinder info, object[] indices, object value);

    public virtual object DeleteIndex(DeleteIndexBinder info, object[] indices); public MetaObject IDynamicObject.GetMetaObject();

}

5、var和dynamic之间的区别

  • **Declared variables
    **The keyword VaR is introduced in C 3.0. The declared variables are of static type, and the type of variables is determined by the compiler at compile time.
    The keyword dynamic is introduced in C 4.0. The declared variables are of dynamic type, and the type of variables is determined by the compiler at run time.
  • **Initialize
    **The variables declared by the keyword var should be initialized at the time of declaration, so that the compiler will determine the type of variables according to the initialized value. If the variable is not initialized, an error is thrown.
    Variables declared by keyword dynamic do not need to initialize variables of this type when declared, because the compiler does not know the type of variables at compile time. If the variable is not initialized, no error will be thrown.
  • **intelliSense的支持
    ** 关键字var支持visual studio中的intelliSense。关键字dynamic不支持visual
    studio中的intelliSense
  • **Apply
    **The keyword var cannot be used for attributes or return values from functions. It can only be used as a local variable in a function.
    The keyword dynamic can be used for attributes or return values from functions.

6. Enhancing the expressive power of c# generics with dynamic

In addition to the following operator overloading, it is also applicable to ordinary method calls. This method is a dynamic duck
The generic parameter constraint mechanism of typing depends on the method search at runtime. Unlike the check at template compilation, it requires the user to ensure that the incoming object meets the corresponding requirements.

static class Calculator

{

    public static T Add<T>(T t1, T t2)

    {

       dynamic d1 = t1;

        dynamic d2 = t2;

        return (T)(d1 + d2);

    }

}



public static void Main(string[] args)

{

    int i = Calculator.Add(1, 2);

    string s = Calculator.Add("abc", "def");

    Console.WriteLine(i + " " + s);

}

二、Named and optional arguments:命名参数和可选参数

1. Declaration of methods with optional parameters:

public StreamReader OpenTextFile(string path, 

Encoding encoding = null, bool detectEncoding = true, int bufferSize = 1024

);

2. Named parameters must be placed last:

OpenTextFile("foo.txt", Encoding.UTF8, 

bufferSize:

 4096);

3. The order of named parameters is unlimited:

OpenTextFile(

bufferSize:

4096, 

path:

 "foo.txt", 

detectEncoding:

 false);

三、Generic co- and contravariance:泛型的协变和逆变

In c#, the following type conversions are illegal:

IList<string> strings = new List<string>();

IList<object> objects = strings;

Because you may do this, and the static check of the compiler cannot find the error:

objects[0] = 5;

string s = strings[0];

In 4.0, in and out keywords can be added when declaring generic interface and delegate, such as:

public interface IEnumerable<out T> : IEnumerable

{

   IEnumerator<T> GetEnumerator();

}


public interface IEnumerator<out T> : IEnumerator

{

   bool MoveNext();

   T Current { get; }

}



public interface IComparer<in T>

{

 public int Compare(T left, T right);

}
  • The out keyword means that t in IEnumerable will only be used in output, and the value will not be changed. In this way, it is safe to convert IEnumerable to IEnumerable type.
  • In means exactly the opposite. It means that t in IComparer will only be used in input, so IComparer can be safely converted to IComparer type.

The former is called co variance covariance and the latter is contra variance inversion.

.Net4.0中使用out/in声明的Interface:

System.Collections.Generic.IEnumerable<out T>

System.Collections.Generic.IEnumerator<out T>

System.Linq.IQueryable<out T>

System.Collections.Generic.IComparer<in T>

System.Collections.Generic.IEqualityComparer<in T>

System.IComparable<in T>

Delegate:

System.Func<in T, …, out R>

System.Action<in T, …>

System.Predicate<in T>

System.Comparison<in T>

System.EventHandler<in T>

4、 Embedded interop types (“nopia”): enable embedded type information and increase the neutrality of programs referencing COM components

In c#, when calling COM objects such as office objects, you often need to write a bunch of unnecessary parameters:

object fileName = "Test.docx";

object missing  = System.Reflection.Missing.Value;

doc.SaveAs(ref fileName,

ref missing, ref missing, ref missing,

ref missing, ref missing, ref missing,

ref missing, ref missing, ref missing,

ref missing, ref missing, ref missing,

ref missing, ref missing, ref missing);

4.0 can be written directly as:

doc.SaveAs("Test.docx");

C#4.0 improves com interaction in the following aspects:

  • Automatic object -> dynamic mapping
  • Optional and named parameters
  • Indexed properties
  • Optional “ref” modifier
  • Interop type embedding (“No PIA”)

A simple explanation of points 1 and 5 is as follows:

In com calls, many input and output types are object, so you must know the exact type of the returned object before calling the corresponding method. With dynamic support in 4.0, variables can be defined as dynamic instead of object when importing these COM interfaces, eliminating forced type conversion.

Pia (primary interop assemblies) is generated according to com API Net
Assembly is generally large. Pia is not required when running in 4.0. The compiler will judge which part of com your program uses
API, only wrap this part with PIA and directly add it to the assembly of your own program.