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());
}
}
}
在我的应用程序中,我遇到了一个我无法理解的 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());
}
}
}