C#4.0

C#4.0

动态绑定

C#4.0引入了一个新的关键字dynamic,用来表示动态类型。dynamic的出现让C#具有了弱语言类型的特性。

关于dynamic的主要规则:

  • 几乎所有CLR类型都可以隐式转换为dynamic
  • 所有dynamic类型的表达式都可以隐式转换为CLR类型
  • 使用dynamic类型值得表达式通常会动态的求值
  • 动态求值表达式的静态类型通常被视为dynamic

编译器对待dynamic的方式与普通的CLR类型不同。任何使用了动态值的表达式都会从根本上改变编译器的行为。编译器不会试图弄懂代码的确切含义,不会恰当的绑定各个成员的访问,不会执行重载决策。它只是通过解析源代码,找出要执行的操作的种类、名称、所设计的参数以及其他相关信息。编译器也不会发出(emit)IL来直接执行代码,而是使用所有必要的信息生成调用DLR的代码。剩下的工作将在执行时进行。

DLR(Dynamic Language Runtime),动态语言运行时,是所有动态语言和C#编译器用来动态执行代码的库。

DLR虽然以运行时为名,但与CLR不在同一个级别(它不涉及JIT编译、本地API奉送、GC等内容)。而是建立在大量.NET 2.0.NET 3.5 的功能之上,特别是DynamicMethodExpression类型。.NET4还扩展了表达式树的API,DLR可以使用它来表示更多的概念。

尽管DLR不直接操作本地代码,但在在某种程度上我们可以认为它做着与CLR类似的工作:正如CLR将IL转换为本地代码一样,DLR将用绑定器、调用点、元对象以及其他各种概念表示的代码转换为表达式树,然后将表达式树编译为IL,最终由CLR编译为本地代码。

不要混淆dynamicvar。用var声明局部变量只是一种简化语法,它要求编译器根据表达式推断出具体数据类型。var关键字只能在方法内部声明局部变量,而dynamic关键字可用于局部变量、字段和参数。表达式不能转型为var,但能转型为dynamic。必须显式初始化用var声明的变量,但无需初始化用dynamic声明的变量。

命名实参/可选参数

命名实参

named argument

有了命名实参,你将不再需要记住或查找形参在所调用方法的形参列表中的顺序。 每个实参的形参都可按形参名称进行指定。

SetName(firstName:"first",middleName:‘middle‘,LastName:‘last‘);

//可以按任意顺序设置实参
SetName(LastName:‘last‘,firstName:"first",middleName:‘middle‘);

可选参数

optional parameter

方法、构造函数、索引器或委托的定义可以指定其形参为必需还是可选。 任何调用都必须为所有必需的形参提供实参,但可以为可选的形参省略实参。

每个可选形参都有一个默认值作为其定义的一部分。 如果没有为该形参发送实参,则使用默认值。

可选参数意味着一些参数是可选的,调用者不必显式指定它们的值,但是必须给可选参数一个默认值。默认值必须为数字或字符串字面量、null、const常量、枚举成员和default(T)操作符。

可选参数必须出现在必需参数之后。

命名实参常常与可选参数同时出现。

public void ExampleMethod(int required, string optionalstr = "default string",
    int optionalint = 10)
{

}
//调用
anExample.ExampleMethod(3, optionalint: 4);

泛型协变和逆变

可变性是指以一种类型安全的方式,将一个对象作为另一个对象来使用。

可变性分为两种:

  • 协变性(Covariance):指返回类型的兼容性,用于向调用者返回某项操作的值,能够使用比原始指定的派生类型的派生程度更大(更具体的)的类型。
  • 逆变性(Contravariance):指参数的兼容性,用于调用者向某项操作传入的值,指能够使用比原始指定的派生类型的派生程度更小(不太具体的,更抽象的)的类型。

可变性摘要:

  • .NET Framework 4 中,可变性参数仅限于泛型接口泛型委托类型
  • 泛型接口或泛型委托类型可以同时具有协变和逆变类型参数。
  • 可变性参数仅适用于引用类型;如果为可变性参数指定值类型,则该类型参数对于生成的构造类型是不变的。
  • 可变性参数不适用于委托组合。

在泛型接口或委托的声明中,C#4使用out修饰符来指定类型参数的协变性,使用in修饰符来指定逆变性。声明完成后,就可以对相关的类型进行隐式转换了。

如果有一个泛型参数标记为out,则代表它是用来输出的,只能作为结果返回;而如果有一个泛型参数标记为in,则代表它是用来输入的,只能作为参数传入。

可变性的转换是引用转换:任何使用了协变和逆变的转换都是引用转换,这意味着转换之后将返回相同的引用。它不会创建新的对象,只是认为现有的引用与目标类型匹配。

我们熟知的Action<T>Func<T>就分别使用了逆变跟协变。

//泛型参数具有逆变性
public delegate void Action<in T>(T obj);
public interface IComparer<in T>
{
    int Compare(T x, T y);
}

//泛型参数具有协变性
public delegate T Func<out T>();
public interface IEnumerable<out T> : IEnumerable
{
    new IEnumerator<T> GetEnumerator();
}

//**************逆变性***************
//明明object不可以转换为string,为啥strComparer可以接收IComparer<object>类型的变量?
//是因为IComparer<in T>的泛型参数具有逆变性
//所以IComparer<string>接口可以使用比string更抽象的object类型
IComparer<object> objComparer = null;
IComparer<string> strComparer = objComparer;
//同理,因为Action<in T>的泛型参数具有逆变性
//所以Action<string>委托可以使用比string更抽象的object类型
Action<object> objAction = (obj) => Console.WriteLine(obj.GetHashCode());
Action<string> strAction = objAction;

//**************协变性***************
//由于IEnumerable<out T>的泛型参数具有协变性
//所以IEnumerable<object>接口可以使用比object更具体的string类型
IEnumerable<string> strEnumerable = new List<string> { };
IEnumerable<object> objEnumerable = strEnumerable;
//同理,因为Func<out T>的泛型参数具有协变性
//所以Func<object>委托可以使用比object更具体的string类型
Func<string> strFunc = () => { return ""; };
Func<object> objFunc = strFunc;

嵌入的互操作类型

.NET Framework 4 开始,公共语言运行时支持将 COM 类型的类型信息直接嵌入到托管程序集中,而不要求托管程序集从互操作程序集中获取 COM 类型的类型信息。 由于嵌入式类型信息仅包含托管程序集实际使用的类型和成员,因此两个托管程序集可能具有相同 COM 类型的不同视图。 每个托管程序集都有不同的 Type 对象来表示其 COM 类型视图。 公共语言运行时支持接口、结构、枚举和委托等不同视图之间的类型等效性。

类型等效性意味着从一个托管程序集传递到另一个托管程序集的 COM 对象可以转换为接收程序集中适当的托管类型。

备注:类型等效性和嵌入式互操作类型简化了使用 COM 组件的应用程序和加载项的部署,因为无需与应用程序一起部署互操作程序集。 如果共享 COM 组件的开发人员希望较早版本的 .NET Framework 使用其组件,他们仍须创建主互操作程序集 (PIA)。

C#4.0

上一篇:c# 指针


下一篇:C#5