C# CustomAttribute 的奇怪行为

C# Strange behavior of CustomAttribute

在我的应用程序中,我遇到了一个我无法理解的 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" 属性装饰的每种类型的 类 映射到一个函数,该函数 return 的值 return 由其自定义属性编辑:

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 类型的函数可能 return "Hi From A" 但奇怪的是,以下代码将 "Hi From B" 打印到控制台!

func();
Console.WriteLine(dic[typeof(X)]());

我是否缺少语言功能?

此行为与属性无关。这是一个经典的 "captured variable" 问题。您在 foreach 循环之外声明 attr 变量,然后在委托内部引用它,因此字典中的每个函数最终都会引用 [=13= 的最后一个值] 通过 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

如果将声明移到循环中,您将获得所需的行为。

static void func()
{
    foreach (var type in typeof(Program).Assembly.GetTypes())
    {
        var attrs = type.GetCustomAttributes(typeof(A)).ToList();
        if(attrs.Any())
        {
            A attr = attrs.First() as A;
            dic.Add(type, () => attr.SayHi());
        }
    }
}