返回题库高级 .NET 刷题C# 选择题 · 第 15 / 50 篇

C# 试题 15:泛型基础

0281 以下代码运行结果是什么?

难度: 实战

var ints = new List<int> { 1, 2, 3 };
object box = ints;
var objs = (List<object>)box;
Console.WriteLine(objs.Count);
  • A. 编译失败,List<int> 不能赋给 object
  • B. 输出 3
  • C. 运行抛 InvalidCastExceptionList<int>List<object> 是运行期不同类型的实例
  • D. 运行抛 ArrayTypeMismatchException
查看答案与解析

正确答案C

解析: .NET 泛型是 reified(类型参数保留到运行期),List<T> 本身不变;强转检查的是对象实际类型 List<int>,它不是 List<object> 的实例,抛 InvalidCastException。这与 Java 泛型擦除后的“强转普遍可过”完全不同。

关键点: List<int>List<object> 是两个不同的运行期类型。

0282 以下代码输出什么?

难度: 进阶

var list = new List<int> { 7 };
int v = list[0];
Console.WriteLine(v);
  • A. 编译失败
  • B. 输出 7,但 Add 与索引读取都会装箱
  • C. 运行抛 InvalidCastException
  • D. 输出 7,存取过程不涉及装箱
查看答案与解析

正确答案D

解析: List<int>int 专门化,元素直接以内联值存储,Add/索引器都不装箱;只有把 int 赋给 object 之类的引用位置才装箱。泛型消除值类型进出的装箱是其核心收益之一。

关键点: 值类型实参的泛型容器不会对元素装箱。

0283 以下代码输出什么?

难度: 进阶

var s = default(string);
var n = default(int?);
Console.WriteLine(s == null);
Console.WriteLine(n == null);
Console.WriteLine(n.HasValue);
  • A. FalseFalseFalse
  • B. TrueTrueTrue
  • C. TrueTrueFalse
  • D. 编译失败
查看答案与解析

正确答案C

解析: default(string)nulldefault(int?) 是”无值”的 Nullable<int>,与 null 比较为 TrueHasValueFalse。两者都表示”空”,但底层完全不同:前者是无引用的引用类型,后者是装箱过的结构体。

关键点: 引用类型与 Nullable<T> 的 default 都是”空”,但机制不同。

0284 以下代码能否编译?

难度: 进阶

var x = default;
Console.WriteLine(x);
  • A. 编译失败,default 字面量无法推断目标类型
  • B. 编译通过,输出 0
  • C. 编译通过,输出 null
  • D. 编译通过,运行抛 NullReferenceException
查看答案与解析

正确答案A

解析: C# 7.1 引入的 default 字面量必须存在可推断的目标类型;var 不提供任何目标类型,编译器无法确定是 intstring 还是别的,直接报错。这与 int x = default;(合法)形成对比。

关键点: 无目标类型的 default 无法编译,var 救不了它。

0285 以下代码输出什么?

难度: 进阶

static string Describe<T>() => default(T) is null ? "null" : "non-null";
Console.WriteLine(Describe<int>());
Console.WriteLine(Describe<string>());
  • A. nullnull
  • B. non-nullnull
  • C. nullnon-null
  • D. 两行都抛异常
查看答案与解析

正确答案B

解析: default(int)0,与 null 比较需要装箱成 0,不是 null;default(string) 才是 null。资深开发者常把 default(T) 一律当成 null,实际上对值类型它是零值。

关键点: default(T) 对值类型是零值而非 null。

0286 以下代码输出什么?

难度: 实战

Type open = typeof(List<>);
Console.WriteLine(open.IsGenericType);
Console.WriteLine(open.IsGenericTypeDefinition);
Console.WriteLine(open.GetGenericArguments()[0].IsGenericParameter);
  • A. TrueTrueTrue
  • B. TrueTrueFalse
  • C. TrueFalseTrue
  • D. 第二行抛异常
查看答案与解析

正确答案A

解析: IsGenericType 对泛型类型定义和构造类型都返回 True,只有 IsGenericTypeDefinition 能区分 List<>(定义)与 List<int>(封闭);定义上的类型实参是 IsGenericParameterTrue 的泛型参数 T,而不是具体类型。

关键点: “开放泛型”与”泛型定义”是两个不同概念,别用 IsGenericType 判断是否已封闭。

0287 以下代码输出什么?

难度: 进阶

Type open = typeof(List<>);
Type closed = open.MakeGenericType(typeof(int));
Console.WriteLine(closed == typeof(List<int>));
Console.WriteLine(open.GetGenericArguments()[0].Name);
  • A. FalseT
  • B. TrueInt32
  • C. 运行抛异常
  • D. TrueT
查看答案与解析

正确答案D

解析: MakeGenericType(typeof(int)) 把开放类型构造为 List<int>,与 typeof(List<int>) 是同一个 Type 对象;定义上的第一个类型参数名是 T(来自泛型定义,不是 Int32)。

关键点: 反射实例化泛型用 MakeGenericType,参数名仍保留定义里的名字。

0288 以下代码运行结果是什么?

难度: 进阶

Type t = typeof(List<int>);
t.MakeGenericType(typeof(string));
  • A. 编译失败
  • B. 返回 List<string>
  • C. 运行抛 InvalidOperationException,已构造类型不能再 MakeGenericType
  • D. 运行抛 ArgumentException
查看答案与解析

正确答案C

解析: MakeGenericType 只接受泛型类型定义(IsGenericTypeDefinition == true)。List<int> 已封闭,再调用抛 InvalidOperationException。若想得到 List<string>,必须拿 typeof(List<>) 来构造。

关键点: 反射构造类型前先确认拿的是定义而不是已封闭类型。

0289 以下代码输出什么?

难度: 实战

class Counter<T>
{
    public static int Count;
}
Counter<int>.Count++;
Counter<string>.Count++;
Counter<int>.Count++;
Console.WriteLine(Counter<int>.Count);
Console.WriteLine(Counter<string>.Count);
  • A. 22
  • B. 21
  • C. 11
  • D. 编译失败
查看答案与解析

正确答案B

解析: CLR 为每个封闭泛型类型单独分配静态存储:Counter<int>Counter<string> 各有一份 CountCounter<int>.Count 自增两次为 2,Counter<string>.Count 自增一次为 1。

关键点: 泛型静态字段按封闭类型隔离,“全局计数”很容易踩坑。

0290 以下代码输出什么?

难度: 进阶

class Holder<T>
{
    public static int Next;
    public static int Id = ++Next;
}
Console.WriteLine(Holder<int>.Id);
Console.WriteLine(Holder<int>.Id);
Console.WriteLine(Holder<string>.Id);
  • A. 111
  • B. 121
  • C. 123
  • D. 编译失败
查看答案与解析

正确答案A

解析: 静态初始化每个封闭类型只执行一次:Holder<int>Id 初始化后恒为 1;Holder<string> 是另一份独立的静态状态,其 Next 也从 0 开始,Id 同样为 1。三个输出都是 1。

关键点: 静态初始化按封闭类型执行一次,别按”共享状态”推导。

0291 关于泛型类型中的静态字段,哪项正确?

难度: 进阶

  • A. 所有泛型实例共享同一份静态字段,与类型实参无关
  • B. 每个封闭泛型类型各有一份独立静态字段,Counter<int>Counter<string> 互不影响
  • C. 静态字段会随类型实参装箱
  • D. 泛型类型不能声明静态字段
查看答案与解析

正确答案B

解析: 泛型类型是”类型模板”,每次用不同类型实参封闭都产生独立的类型,静态字段随之独立。跨封闭类型共享状态需要显式用 static 非泛型辅助类或 ConcurrentDictionary<Type, ...> 之类的设计。

关键点: 泛型静态字段 = 按封闭类型隔离,不跨类型共享。

0292 以下代码能否编译?

难度: 实战

static T M<T>(T a, T b) => a;
var r = M(1, 2L);
  • A. 编译失败,intlong 之间无法推断出单一 T
  • B. 编译通过,T 推断为 long
  • C. 编译通过,T 推断为 object
  • D. 编译通过,T 推断为 int2L 被截断
查看答案与解析

正确答案A

解析: 泛型方法类型推断不做”最佳公共类型”合并:intlong 之间没有可同时满足 T 的隐式转换(提升不会发生在推断阶段),报 CS0411。必须显式写类型实参或让实参类型一致。

关键点: 推断不做数值提升/合并,M(1, 2L) 是经典编译失败。

0293 以下代码输出什么?

难度: 进阶

static T M<T>(T a, T b) => a;
Console.WriteLine(M("a", null));
  • A. 编译失败
  • B. 输出空串
  • C. 运行抛 NullReferenceException
  • D. 输出 aT"a" 推断为 stringnull 作为 string 实参合法
查看答案与解析

正确答案D

解析: 推断先从 "a" 得到 T = string,随后 null 字面量按 string 转换即可,编译通过并输出 anull 本身不能独立推断类型,但可以配合其它实参完成推断。

关键点: null 字面量无法单独提供类型信息,但有其它实参时会被”套用”。

0294 以下代码能否编译?

难度: 实战

static T M<T>(T x) => x;
var s = M(null);
  • A. 编译失败,无法从 null 推断 T
  • B. 编译通过,T 推断为 string
  • C. 编译通过,T 推断为 object
  • D. 编译通过,运行抛 ArgumentNullException
查看答案与解析

正确答案A

解析: null 字面量没有任何类型信息,单独作为实参时推断失败(CS0411)。必须显式指定,如 M<string?>(null)。这与上题的”"a" 提供类型后 null 可套用”形成对照。

关键点: 单靠 null 实参无法完成泛型推断。

0295 关于泛型方法类型推断,哪项正确?

难度: 进阶

  • A. 编译器会根据返回值被赋给的变量类型推断 T
  • B. 推断基于实参与上下文在编译期进行,返回类型通常不参与推断
  • C. 推断发生在运行时
  • D. 推断只适用于值类型实参
查看答案与解析

正确答案B

解析: 泛型推断只从实参及调用上下文推导类型参数,返回值位置通常不作为推断来源;所以 static T M<T>() => default; 不能靠 var x = M(); 推断。推断是编译期行为,与运行时无关。

关键点: “按返回值推断泛型”是错误直觉,返回类型一般不参与推断。

0296 以下代码能否编译?

难度: 实战

static T M<T>(T x) => x;
Console.WriteLine(M<int>(1.5));
  • A. 编译通过,输出 1
  • B. 编译通过,输出 1.5
  • C. 编译失败,double 不能隐式转换为 int
  • D. 编译通过,运行抛 InvalidCastException
查看答案与解析

正确答案C

解析: 显式指定类型实参后参数类型固定为 int1.5double,二者没有隐式转换(数值转换里也没有 double→int 的隐式方向),编译失败。显式类型实参取消推断,但普通重载决议与转换规则照常生效。

关键点: 显式类型实参不等于”帮忙转换”,类型不符照样编译失败。

0297 以下代码输出什么?

难度: 实战

IEnumerable<object> e = new List<string> { "ok" };
foreach (var item in e)
{
    Console.WriteLine(item);
}
  • A. 编译失败,List<string> 不能转换为 IEnumerable<object>
  • B. 编译通过,输出 okIEnumerable<out T> 协变允许引用类型转换
  • C. 编译通过,运行抛 InvalidCastException
  • D. 编译通过,什么都不输出
查看答案与解析

正确答案B

解析: 转换链是 List<string>IEnumerable<string> →(协变)IEnumerable<object>,引用类型之间全部合法,运行期无异常。协变只存在于只读接口/委托等”只出不进”的位置,List<T> 本身不变。

关键点: 协变是接口/委托层面的转换,List<object> = List<string> 依然不合法。

0298 关于开放泛型类型(List<>)与封闭泛型类型(List<int>),哪项正确?

难度: 进阶

  • A. 开放类型含未绑定类型参数,不能直接实例化;封闭类型参数全部绑定,可正常使用
  • B. 两者在运行时是同一个 Type 对象
  • C. 开放类型可以直接 new 出实例
  • D. 封闭类型不能用于反射
查看答案与解析

正确答案A

解析: List<> 是泛型类型定义,其中 T 未绑定,不能 new List<>(),只能用于反射构造;List<int> 全部绑定,可直接实例化。开放类型与封闭类型是运行时不同的 Type 对象,ContainsGenericParameters 可区分二者。

关键点: 开放类型不可实例化,只能作为类型定义存在。

0299 以下代码输出什么?

难度: 实战

static string TypeName<T>() => typeof(T).Name;
Console.WriteLine(TypeName<int>());
  • A. T
  • B. Int32
  • C. System.Int32
  • D. 编译失败
查看答案与解析

正确答案B

解析: .NET 泛型是 reified:运行期 typeof(T) 拿到的是真实类型 System.Int32,其 NameInt32FullName 才是 System.Int32)。这与 Java 的泛型擦除(运行期只剩 Object)本质不同。

关键点: 泛型类型参数在运行期保留,typeof(T) 返回实际类型。

0300 以下代码输出什么?

难度: 进阶

static void M<T>(Func<T> f) => Console.WriteLine(typeof(T).Name);
M(() => 42);
  • A. 编译失败,lambda 不参与类型推断
  • B. 编译通过,输出 Object
  • C. 编译通过,输出 Int32,编译器从 lambda 返回类型推断 T
  • D. 编译通过,输出 T
查看答案与解析

正确答案C

解析: C# 10 起,无显式返回类型的 lambda 其返回类型可参与泛型方法推断:() => 42 的返回类型是 int,于是 T = int,输出 Int32。这是”返回类型通常不参与推断”的少数例外,推断来源是 lambda 体。

关键点: 表达式体 lambda 的返回类型可以作为推断来源。

官方资料

当前分类

C# 选择题

查看全部分类 →
  1. 13C# 试题 13:枚举与元组20 题
  2. 14C# 试题 14:模式匹配20 题
  3. 15C# 试题 15:泛型基础20 题
  4. 16C# 试题 16:泛型约束与型变20 题
  5. 17C# 试题 17:委托与 Lambda20 题
ESC

输入关键词开始搜索