var是编译期静态类型推断,编译器根据赋值表达式确定具体类型,后续操作受限于该类型的成员;dynamic是运行期动态绑定,类型检查推迟到运行时,允许调用任意方法或访问属性而不会在编译时报错。两者虽然都省略了显式类型声明,但var生成的il代码包含确切类型信息,而dynamic会生成特殊的运行时绑定调用。

var在编译时如何确定类型?
var关键字要求变量必须在使用时立即初始化,且初始化的表达式必须能推导出一个非空的具体类型。编译器在编译阶段就会分析右侧表达式的类型,并将左侧变量的类型替换为该具体类型。这意味着var只是语法糖,它不会改变程序的类型安全性,也不会影响性能。例如,使用var x = 10;后,x的类型就是int,如果尝试调用x.ToString()是合法的,但如果尝试调用x.NonExistentMethod(),编译器会报错。

using System;
public class Program
{
public static void Main()
{
var number = 42; // 编译器推断为 int
var text = "Hello"; // 编译器推断为 string
Console.WriteLine(number.GetType()); // 输出: System.Int32
Console.WriteLine(text.GetType()); // 输出: System.String
// 以下代码会导致编译错误:
// number = "Not a number"; // Error: Cannot implicitly convert type 'string' to 'int'
}
}
dynamic在运行时如何处理调用?
dynamic关键字告诉编译器放弃对该变量的静态类型检查,将其视为object,并在运行时通过System.Runtime.CompilerServices.CallSite机制进行动态分派。这意味着你可以在dynamic变量上调用任何方法或访问任何属性,即使这些成员在编译时并不存在。如果运行时对象不支持该操作,将会抛出RuntimeBinderException。这种灵活性使得dynamic非常适合处理COM对象、动态语言(如Python或JavaScript)交互或JSON解析等场景。

using System;
using System.Dynamic;
public class Program
{
public static void Main()
{
dynamic obj = new { Name = "Alice", Age = 30 };
Console.WriteLine(obj.Name); // 输出: Alice
Console.WriteLine(obj.Age); // 输出: 30
// 以下代码在编译时不会报错,但在运行时会抛出异常:
try
{
obj.NonExistentProperty;
}
catch (Microsoft.CSharp.RuntimeBinder.RuntimeBinderException ex)
{
Console.WriteLine("Runtime Error: " + ex.Message);
}
}
}
当dynamic对象调用不存在的方法时会发生什么?
当dynamic对象调用不存在的方法时,编译器会生成一组用于动态绑定的代码,这些代码会在运行时查找并执行实际的调用逻辑。如果目标对象没有对应的方法,或者参数不匹配,运行时绑定器会抛出RuntimeBinderException。这种行为与var形成鲜明对比,因为var在编译阶段就会阻止对不存在成员的访问。因此,使用dynamic时需要特别注意异常处理,以避免运行时崩溃。











