显式声明变量必须写明类型,类型名在变量名前,编译器不推断;var是编译期类型推断语法糖,仅限局部变量且必须初始化;dynamic绕过编译检查,运行时解析,非var升级版。

显式声明变量必须写明类型
不带 var 的变量声明,类型名必须出现在变量名前,编译器不会推断。比如 int count = 0;、string name = null;、List<int> numbers = new List<int>();</int></int>。这种写法清晰、可读性强,尤其适合类型名本身能传达语义的场景(如 HttpClient client),也便于 IDE 显示准确的类型信息。
常见错误是漏写类型或误用关键字:var count = 0; 看似简单,但若后续想改成 count = 3.14; 就会编译失败——因为 var 推出的是 int,不是 dynamic。
var 只能在局部变量中使用,且必须初始化
var 是编译器在编译期根据右侧表达式推断类型的语法糖,它不是运行时类型,也不等价于 object 或 dynamic。以下写法全部非法:
-
var x;—— 编译报错:Implicitly-typed local variables must be initialized -
var y = null;—— 编译报错:Cannot assign <null> to an implicitly-typed local variable</null> -
public var Name { get; set; }—— 类字段、属性、返回值、参数都不能用var
正确用法示例:var items = new Dictionary<string int>();</string>、var result = GetResponseAsync().Result;。注意:如果 GetResponseAsync() 返回 Task<string></string>,那 result 类型就是 string,不是 Task<string></string>。
引用类型和值类型在初始化时的行为差异
值类型(如 int、DateTime)声明即有默认值(0、DateTime.MinValue),但未初始化就使用仍可能触发警告或运行时异常;引用类型(如 string、List<t></t>)声明后默认为 null,直接调用方法会抛出 NullReferenceException。
推荐做法是显式初始化,尤其是引用类型:
-
string message = string.Empty;或string? message = null;(启用可空引用后) -
List<int> list = new();</int>(C# 9+ 支持目标类型 new,比new List<int>()</int>更简洁) -
int? nullableInt = null;—— 显式表示可空,避免误用默认值0
别把 dynamic 当成 var 的升级版
dynamic 绕过编译期类型检查,所有成员访问都在运行时解析。它和 var 完全不同:var 是静态类型、编译期确定;dynamic 是动态绑定、运行时才查类型。
典型误用场景:
- 用
dynamic obj = GetJsonData();替代强类型模型 —— 导致 IDE 无智能提示、编译不报错但运行时崩 - 在循环里反复访问
obj.Name、obj.Age—— 性能比强类型低一个数量级
真正需要 dynamic 的情况极少,比如与 COM 对象交互、反射调用不确定结构的类型,或封装高度泛化的 DSL 解析器。日常业务逻辑中,优先建模为具体类或使用 JsonNode / JsonDocument。
类型推断和初始化时机是 C# 变量定义中最容易混淆的两个点,尤其是 var 和 dynamic 的边界、以及引用类型默认 null 带来的空引用风险,这些在调试时往往表现为“明明声明了却报空”。


















