C#自定义属性与反射的异常行为技术咨询
问题分析与解决方案
你遇到的这个问题其实是C#里闭包的一个常见“陷阱”——闭包捕获的是变量的引用,而不是迭代时的变量值,这也是你忽略的核心语言特性。
问题根源
在你的func方法中,attr是在循环外部声明的变量:
A attr; foreach (var type in typeof(Program).Assembly.GetTypes()) { // ... attr = attrs.First() as A; dic.Add(type, () => attr.SayHi()); }
你创建的lambda表达式() => attr.SayHi()并没有捕获当前迭代中attr的具体值,而是捕获了attr这个变量本身的引用。当循环结束时,attr最终指向的是最后一个被处理的属性实例(也就是类Y上的B属性)。所以当你后续调用dic[typeof(X)]()时,lambda会使用attr的最终值,自然返回"Hi From B"。
修复方案
解决方法很简单:在循环内部声明一个局部变量,把当前迭代的属性实例赋值给这个局部变量,让闭包捕获这个局部变量(每个迭代的局部变量都是独立的,持有当前迭代的属性值):
static Dictionary<Type, Func<string>> dic = new Dictionary<Type, Func<string>>(); static void func() { foreach (var type in typeof(Program).Assembly.GetTypes()) { var attrs = type.GetCustomAttributes(typeof(A)).ToList(); if(attrs.Any()) { // 循环内声明局部变量,保存当前迭代的属性实例 var currentAttr = attrs.First() as A; dic.Add(type, () => currentAttr.SayHi()); } } }
修改后,再次执行代码:
func(); Console.WriteLine(dic[typeof(X)]()); // 输出 "Hi From A" Console.WriteLine(dic[typeof(Y)]()); // 输出 "Hi From B"
就能得到符合预期的结果了。
内容的提问来源于stack exchange,提问作者Pharaz Fadaei
相关产品推荐
相关产品推荐

