错误 CS0133:将函数的结果分配给 C#.net 中的 const

发布于 2024-09-03 06:35:17 字数 680 浏览 7 评论 0原文

尝试清理范围并避免可能多次调用 RegisterWindowMessage。
目前有一个类与以下成员一起使用一次,

[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern int RegisterWindowMessage(string lpString);

private int m_message = RegisterWindowMessage("MY_MSG"); 

因为我们只有一个实例,这似乎没问题,但认为使用起来会更整洁。根据我对 C# 的基本理解,这应该调用 RegisterWindowMessage 并将结果分配给 int 并且不允许它更改。

private const int message = RegisterWindowMessage("MY_MSG"); 

但是尝试这样做会导致

error CS0133: The expression being assigned to 'someclass.messageEvent' must be constant

现在我很困惑,这是否意味着之前每次使用 m_message 时都会分配并调用该函数,是否还缺少其他内容?

Trying to tidy up scope and avoid possible multiple calls to RegisterWindowMessage.
Currently have a class used once with the following member

[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern int RegisterWindowMessage(string lpString);

private int m_message = RegisterWindowMessage("MY_MSG"); 

As we only have one instance this seems ok, but think it would be more tidy to use. With my basic C# understanding this should call RegisterWindowMessage and assign the result to int and not allow it to change.

private const int message = RegisterWindowMessage("MY_MSG"); 

however attempting to do so leads to a

error CS0133: The expression being assigned to 'someclass.messageEvent' must be constant

so now I'm confused, does this mean the function was being assigned and called each time m_message was used previously, is there something else missing?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

过气美图社 2024-09-10 06:35:17

const 字段必须是编译时常量。如果您只是想要在初始赋值1之后执行时不会更改的内容,请将其设置为只读:

private static readonly int Message = RegisterWindowMessage("MY_MSG");

请注意,我已将其设置为静态,const 是隐式的。这意味着 RegisterWindowMessage 只会为此 AppDomain 调用一次,这就是我认为您想要的。

编辑:汉斯是对的,你应该检查返回值。您可以在第一次使用它时或在初始化类型时执行此操作 - 通常类型初始值设定项抛出异常不是一个好主意,但您应该看看会产生什么影响。


1 严格来说,静态只读字段可以在声明中或静态构造函数中赋值;可以在声明或任何实例构造函数中分配实例只读字段。它可以被分配多次,这通常没有用,但偶尔会有用。

A const field has to be a compile-time constant. If you just want something which won't change at execution time after initial assignment1, make it readonly:

private static readonly int Message = RegisterWindowMessage("MY_MSG");

Note that I've made this static, which const is implicitly. This means RegisterWindowMessage will only be called once for this AppDomain, which is what I think you want.

EDIT: Hans is right, you should check the return value. You could either do that when you first use it, or when the type is initialized - usually it's a bad idea for type initializers to throw exceptions, but you should see what the impact is.


1 Strictly speaking, a static readonly field can be assigned in the declaration or in the static constructor; an instance readonly field can be assigned in the declaration or in any instance constructor. It can be assigned multiple times, which is usually not useful, but can be just occasionally.

千寻… 2024-09-10 06:35:17

这里还有另一个考虑因素。 RegisterWindowMessage() 可能会失败,您确实需要检查这一点。当出现问题时使用它返回的 0 将非常难以诊断。

这就消除了直接在只读声明中对其进行初始化的情况。您可以改用静态构造函数。问题是异常消息将被隐藏在 InnerException 中。也许还可以,因为失败很少见。

最好的解决方案是延迟调用 API 的静态属性 getter:

private int m_message

public static int message {
  get {
    if (m_message == 0) {
      m_message = RegisterWindowMessage("blah");
      if (m_message == 0) throw new Win32Exception();
    }
    return m_message;
  }
}

如果可能从不同线程调用,请使用众所周知的锁定模式。

There is another consideration here. RegisterWindowMessage() can fail, you really need to check for that. Using the 0 it returns when something is wrong is going to be horribly difficult to diagnose otherwise.

That knocks initializing it directly in the readonly declaration out. You could use a static constructor instead. Problem with that is that the exception message will be buried in an InnerException. Kinda okay perhaps since failure will be rare.

The best solution is a static property getter that lazily calls the API:

private int m_message

public static int message {
  get {
    if (m_message == 0) {
      m_message = RegisterWindowMessage("blah");
      if (m_message == 0) throw new Win32Exception();
    }
    return m_message;
  }
}

Use well-known locking patterns if this might be called from different threads.

终遇你 2024-09-10 06:35:17

要添加 Hans 给出的答案,您可以做得比简单地抛出空 Win32Exception 更好。这适用于任何使用 GetLastError 的 API 调用:

[DllImport("user32.dll", SetLastError = true)]
extern static int RegisterWindowMessage(string lpString);

if (m_message == 0)
    throw new Win32Exception(Marshal.GetLastWin32Error());

这将产生更具信息性的异常。

To add to the answer that Hans gave, you can do better than simply throwing an empty Win32Exception. This applies to any API call that uses GetLastError:

[DllImport("user32.dll", SetLastError = true)]
extern static int RegisterWindowMessage(string lpString);

if (m_message == 0)
    throw new Win32Exception(Marshal.GetLastWin32Error());

That will produce a more informative exception.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文