在我的应用程序中,我遇到了一个我无法理解的CustomAttributes和Reflection的奇怪情况,我试图减少问题。假设我有以下自定义属性:
class A : Attribute
{
public virtual string SayHi()
{
return "Hi From A";
}
}
class B : A
{
public override string SayHi()
{
return "Hi From B";
}
}
以下课程使用自定义属性进行修饰:
[A]
class X
{ }
[B]
class Y
{ }
在下面的方法中,我映射用" A"装饰的每种类型的类。属性为返回其自定义属性返回的值的函数:
static Dictionary<Type, Func<string>> dic = new Dictionary<Type, Func<string>>();
static void func()
{
A attr;
foreach (var type in typeof(Program).Assembly.GetTypes())
{
var attrs = type.GetCustomAttributes(typeof(A)).ToList();
if(attrs.Any())
{
attr = attrs.First() as A;
dic.Add(type, () => attr.SayHi());
}
}
}
映射到X类型的函数可能返回&#34; Hi来自A&#34;但奇怪的是,以下代码打印出来&#34; Hi来自B&#34;到控制台!
func();
Console.WriteLine(dic[typeof(X)]());
我错过了语言功能吗?
答案 0 :(得分:1)
此行为与属性无关。这是一个经典的“捕获变量”问题。你在attr
循环之外声明foreach
变量,然后在委托中引用它,所以字典中的每个函数最终都会引用{{1}的最后一个值。在通过attr
。
更简单的复制如下:
foreach
输出:
int x;
var actions = new List<Action>();
for (int i = 0; i < 3; i++)
{
x = i;
actions.Add(() => Console.WriteLine(x));
}
foreach (var action in actions)
{
action();
}
如果您将声明移动到循环中,您将获得您正在寻找的行为。
2
2
2