编译器生成的事件的支持字段是否总是保证使用与事件相同的名称? [英] Is the backing field of a compiler generated event always guaranteed to use the same name as the event?

查看:170
本文介绍了编译器生成的事件的支持字段是否总是保证使用与事件相同的名称?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

C#允许我们创建自定义事件访问器

Action _custom;
public event Action Custom
{
    add { _custom = (Action)Delegate.Combine( _custom, value ); }
    remove { _custom = (Action)Delegate.Remove( _custom, value ); }
}



如果不指定它们,编译器为您创建。 C#语言规范:


编译类似字段的事件时,编译器会自动创建
存储来保存委托,

When compiling a field-like event, the compiler automatically creates storage to hold the delegate, and creates accessors for the event that add or remove event handlers to the delegate field.

反编译的源代码使用 dotPeek 一个简单的公共事件Action Public; 如下所示:

The decompiled source code using dotPeek for a simple public event Action Public; looks as follows:

  private Action Public;

  public event Action Public
  {
    add
    {
      Action action = this.Public;
      Action comparand;
      do
      {
        comparand = action;
        action = Interlocked.CompareExchange<Action>(
                     ref this.Public, comparand + value, comparand);
      }
      while (action != comparand);
    }
    remove
    {
      Action action = this.Public;
      Action comparand;
      do
      {
        comparand = action;
        action = Interlocked.CompareExchange<Action>(
                    ref this.Public, comparand - value, comparand);
      }
      while (action != comparand);
    }
  }

值得注意的是字段和事件使用相同的名称。这导致某些人得出结论,通过查找类中的字段,您可以在反射期间找到关于背景字段的信息与事件的名称相同。我实现这个如下:

Noteworthy is that the field and the event use the same name. This has led some people to conclude that you can find information about the backing field during reflection by looking up the field in the class with the same name as the event. I implemented this as follows:

public static FieldInfo GetFieldInfo( this EventInfo eventInfo )
{
    Contract.Requires( eventInfo != null );

    return eventInfo.DeclaringType.GetField(
        eventInfo.Name,
        BindingFlags.DeclaredOnly | BindingFlags.Instance |
            BindingFlags.Public | BindingFlags.NonPublic );
}

这样可以工作,但会引发一个问题:编译器生成的事件总是保证使用与事件相同的名称

This works, but raises the question: Is the backing field of a compiler generated event always guaranteed to use the same name as the event?

不可能创建自定义事件访问器访问同名的代理使用Visual Studio。这会导致以下消息:已声明具有相同名称的成员。我想知道您是否可以得出结论,没有可用的具有相同名称的后备委托的任何事件都是具有自定义

It's not possible to create custom event accessors which access a delegate with the same name using Visual Studio. This results in the message: "Member with the same name is already declared." I am wondering whether you could conclude that any event for which no backing delegate with the same name is available is an event with custom accessors.

推荐答案


编译器生成的事件的支持字段总是保证使用相同的名称作为活动?

Is the backing field of a compiler generated event always guaranteed to use the same name as the event?

Jon和Marc完全正确地回答否。

Jon and Marc are entirely correct to answer "No".

这是编译器的非文档实现细节,由规范明确指出,随时可能更改。

This is an undocumented implementation detail of the compiler, explicitly noted by the specification as such, and subject to change at any time.

在实践中,不太可能改变。我们使用的事实,字段和事件有相同的名称,尽可能最简单的方法在编译器中将它们在逻辑上相互关联。

In practice, this is unlikely to change. We use the fact that the field and the event have the same name as the simplest possible way to associate them logically with each other in the compiler.


无法创建自定义事件访问器,使用Visual Studio访问具有相同名称的代理。这将产生消息:已声明具有相同名称的成员。

It's not possible to create custom event accessors which access a delegate with the same name using Visual Studio. This results in the message: "Member with the same name is already declared."

正确。


您是否可以得出结论:任何没有相同名称的委托代理的事件都是具有自定义访问器的事件。

I am wondering whether you could conclude that any event for which no backing delegate with the same name is available is an event with custom accessors.

不舒服做出这样的结论。如果你知道所讨论的程序集是从C#编译器发出的,你可以得出这个结论。但是我们不是在城里唯一的游戏,当涉及到发射组件。你可以用ILDASM做一些很奇怪的东西。

I would not be comfortable making such a conclusion. You might be able to make that conclusion if you knew that the assembly in question had been emitted from the C# compiler. But we are not the only game in town when it comes to emitting assemblies. You can do some pretty weird stuff with ILDASM.

我可以问你为什么要知道这些东西?我同意Marc;如果你通过Reflection访问一个字段,你可能会做错了。你应该能够访问类中的字段没有问题(因为它只是一个私有字段),并且从类外面,你没有看到另一个类的私有实现细节的业务。 使用反射来执行围绕访问者施加的线程安全性的终极操作是特别糟糕的。这些访问器是为了您的保护;不要绕过他们。

Can I ask why you want to know this stuff? I agree with Marc; if you are accessing a field via Reflection, you're probably doing it wrong. You should be able to access the field within the class no problem (because it is just a private field) and from outside the class, you have no business looking at the private implementation details of another class. It is particularly egregious to use reflection to do an end-run around the thread safety imposed by the accessors. Those accessors are there for your protection; don't run around them.

这篇关于编译器生成的事件的支持字段是否总是保证使用与事件相同的名称?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆