进阶
题目1
请实做 Convert 方法并告知原因及其思路
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
public class Teacher
{
public string Name { get; set; }
public int Age { get; set; }
}
public class Student
{
public string Name { get; set; }
public int Age { get; set; }
}
public static void Action()
{
var teacher = new Teacher()
{
Name = "John",
Age = 26
};
Student a = Convert<Teacher, Student>(teacher);
Person b = Convert<Teacher, Person>(teacher);
}
public static T2 Convert<T1, T2>(T1 obj)
{
throw new NotImplementedException();
}解析如下
-
反射
if (obj == null) return default; // 获取目标类型的空参构造函数 var targetType = typeof(T2); var constructor = targetType.GetConstructor(Type.EmptyTypes); if (constructor == null) throw new InvalidOperationException($"{targetType.Name} 必须有无参构造函数"); // 创建目标对象 var result = (T2)constructor.Invoke(null); // 复制同名属性 var sourceProperties = typeof(T1).GetProperties(BindingFlags.Public | BindingFlags.Instance); var targetProperties = targetType.GetProperties(BindingFlags.Public | BindingFlags.Instance) .Where(p => p.CanWrite); foreach (var sourceProp in sourceProperties) { var targetProp = targetProperties.FirstOrDefault(p => p.Name == sourceProp.Name); if (targetProp != null) { var value = sourceProp.GetValue(obj); targetProp.SetValue(result, value); } } return result; -
序列化
var json = JsonSerializer.Serialize(obj); return JsonSerializer.Deserialize<T2>(json);
题目2
请简述下述程序打印结果,以及原因?
public static void Action()
{
int filterCount = 0;
var colors = new List<string> { "Red", "Green", "Blue" }
.Where(x =>
{
filterCount++;
return x.StartsWith("G");
}).OrderBy(x => x);
Console.WriteLine(filterCount);
Console.WriteLine(colors.Count());
Console.WriteLine(filterCount);
}输出
0
1
3核心原因在于 LINQ 的延迟执行。查询定义时 (Where, OrderBy) 不执行 lambda,只有在需要结果(如调用 Count(), ToList(), foreach 等)时,查询才会被执行,导致 Where 中的 filterCount++ 在 colors.Count() 被调用时才真正对原始列表的每个元素执行。
题目3
请优化 Action 中的方法逻辑并告知其思路
public class Booking
{
public int Id { get; set; }
public decimal Price { get; set; }
public DateTime CreateTime { get; set; }
}
/// <summary>
/// 打印月销售额
/// </summary>
/// <param name="bookings">假设 bookings 有 50w 的元素,如何优化?</param>
public static void Action(List<Booking> bookings)
{
for (int i = 1; i <= 12; i++)
{
decimal totalPrice = bookings
.Where(x => x.CreateTime.Month == i)
.Sum(x => x.Price);
Console.WriteLine($"{i}月总销售额:{totalPrice}");
}
}-
LINQ with GroupBy
public static void ActionOptimize(List<Booking> bookings) { var dictionary = bookings .GroupBy(b => b.CreateTime.Month) .ToDictionary(g => g.Key, g => g.Sum(b => b.Price)); for (int i = 1; i <= 12; i++) { Console.WriteLine(dictionary.TryGetValue(i, out var totalPrice) ? $"{i}月总销售额:{totalPrice}" : $"{i}月总销售额:0"); } } -
并行计算
public static void ActionParallel(List<Booking> bookings) { var monthlyTotals = new ConcurrentDictionary<int, decimal>(); // 并行分组计算 Parallel.ForEach( bookings, booking => { int month = booking.CreateTime.Month; monthlyTotals.AddOrUpdate(month, booking.Price, (_, existing) => existing + booking.Price); }); for (int month = 1; month <= 12; month++) { decimal totalPrice = monthlyTotals.TryGetValue(month, out var sum) ? sum : 0; Console.WriteLine($"{month}月总销售额:totalPrice"); } }
题目4
请简述下述程序打印结果,以及原因?
public class Caching<T>
{
private static ConcurrentDictionary<string, object> CacheDict = new();
public void SetValue(string key, T value)
{
CacheDict.AddOrUpdate(key, value, (key, lastValue) =>
{
return value;
});
}
public object this[string key]
{
get { return CacheDict[key];}
set { CacheDict[key] = value;}
}
}
public static void Action()
{
var names = new Caching<string>();
names.SetValue("John", "John");
var emails = new Caching<string>();
emails.SetValue("John", "John@cc.com");
var ages = new Caching<int>();
ages.SetValue("John", 26);
Console.WriteLine(names["John"]);
Console.WriteLine(emails["John"]);
Console.WriteLine(ages["John"]);
}输出如下
John@cc.com
John@cc.com
26关键在于理解 C# 泛型类的静态成员特性:每个具体的泛型类型实例化(如 Caching<string> 和 Caching<int>)拥有自己独立的静态成员副本。因此,names 和 emails 共享一个字典,而 ages 使用另一个完全不同的字典,导致了最终的输出结果。
题目5
请简述下述程序打印结果,以及原因?
delegate double MyDelegate(int num);
public static void Exec()
{
var myDelegate = new MyDelegate(Run1);
myDelegate += Run2;
Console.WriteLine($"结果: {myDelegate(100)}");
}
static double Run1(int num)
{
var result = num * 0.1;
Console.WriteLine($"Run1-{result}");
return result;
}
static double Run2(int num)
{
var result = num * 0.2;
Console.WriteLine($"Run1-{result}");
return result;
}输出
Run1-10
Run1-20
结果: 20多播委托会按照方法添加的顺序依次执行所有绑定的方法。每个方法都会执行其内部的逻辑(包括 Console.WriteLine)。但是,整个委托调用的返回值仅仅是最后一个被调用的方法的返回值。
题目6
请简述下述程序打印结果,以及原因?
public static void Action()
{
var person = new Person()
{
Name = "John",
Age = 1
};
var actions = new List<Action>();
for (int i = 0; i < 3; i++)
{
actions.Add(() =>
{
person.Age = person.Age * i;
Console.WriteLine($"age: {person.Age}");
});
}
foreach (var action in actions)
{
action.Invoke();
}
}输出
age: 3
age: 9
age: 27所有添加到 actions 列表中的 Lambda 表达式在执行时,都会使用循环变量 i 的最终值(即 3),并且它们都会操作同一个 person 对象的 Age 属性,导致 Age 的值在前一次计算的基础上进行累积性的乘法。