.net - 关于构造函数的代码分析警告

标签 .net vb.net constructor new-operator code-analysis

我编写了一个类来执行系统范围的热键操作,这是唯一的构造函数:

''' <summary>
''' Creates a new system-wide hotkey.
''' </summary>
''' <param name="Modifier">The keys that must be pressed in combination with the specified key.</param>
''' <param name="Key">The key used for the hotkey.</param>
''' <exception cref="IsRegisteredException"></exception>
<DebuggerStepperBoundary()>
Public Sub New(ByVal Modifier As HotkeyModifier, ByVal Key As Keys)

    Me.CreateHandle(New CreateParams)

    Me.PressEventArgs.ID = GetHashCode()
    Me.PressEventArgs.Key = Key
    Me.PressEventArgs.Modifier = Modifier

    If Not NativeMethods.RegisterHotKey(Me.Handle,
                                        Me.PressEventArgs.ID,
                                        Me.PressEventArgs.Modifier,
                                        Me.PressEventArgs.Key) Then

        Throw New IsRegisteredException

    End If

End Sub

项目的代码分析是这样说的:

CA2214 Do not call overridable methods in constructors 'GlobalHotkey.New(GlobalHotkey.HotkeyModifier, Keys)' contains a call chain that results in a call to a virtual method defined by the class. Review the following call stack for unintended consequences:

GlobalHotkey..ctor(GlobalHotkey+HotkeyModifier, Keys) NativeWindow.CreateHandle(CreateParams):Void Object.GetHashCode():Int32 Color .NET GlobalHorkey.vb 213

PS:第213行是这样的:

Public Sub New(ByVal Modifier As HotkeyModifier, ByVal Key As Keys)

我需要做什么来避免这种冲突?

UPDATE

进入 NativeMethods 类...:

    <DllImport("user32.dll", SetLastError:=True)>
    Public Shared Function RegisterHotKey(
                  ByVal hWnd As IntPtr,
                  ByVal id As Integer,
                  ByVal fsModifiers As UInteger,
                  ByVal vk As UInteger
    ) As <MarshalAs(UnmanagedType.Bool)> Boolean
    End Function

UPDATE 2

这是完整的类:

#Region " Usage Examples "

'Public Class Form1

'    ''' <summary>
'    ''' Stores the system-wide hotkey object.
'    ''' </summary>
'    Private WithEvents Hotkey As GlobalHotkey = Nothing

'    ''' <summary>
'    ''' Initializes a new instance of the <see cref="Form1"/> class.
'    ''' </summary>
'    Public Sub New()

'        InitializeComponent()

'        ' Registers a new global hotkey on the system. (Alt + Ctrl + A)
'        Hotkey = New GlobalHotkey(GlobalHotkey.HotkeyModifier.Alt Or GlobalHotkey.HotkeyModifier.Ctrl, Keys.A)

'        ' Replaces the current registered hotkey with a new global hotkey on the system. (Alt + Escape)
'        Hotkey = New GlobalHotkey([Enum].Parse(GetType(GlobalHotkey.HotkeyModifier), "Alt", True),
'                                  [Enum].Parse(GetType(Keys), "Escape", True))

'    End Sub

'    ''' <summary>
'    ''' Handles the Press event of the HotKey control.
'    ''' </summary>
'    Private Sub HotKey_Press(ByVal sender As Object, ByVal e As GlobalHotkey.HotKeyEventArgs) _
'    Handles Hotkey.Press

'        MsgBox(e.ID)
'        MsgBox(e.Key.ToString)
'        MsgBox(e.Modifier.ToString)

'    End Sub

'End Class

#End Region

#Region " Imports "

Imports System.Runtime.InteropServices

#End Region

#Region " Global Hotkey "

''' <summary>
''' Class to perform system-wide hotkey operations.
''' </summary>
Class GlobalHotkey
    Inherits NativeWindow
    Implements IDisposable

#Region " API "

    ''' <summary>
    ''' Native API Methods.
    ''' </summary>
    Public Class NativeMethods

        ''' <summary>
        ''' Defines a system-wide hotkey.
        ''' </summary>
        ''' <param name="hWnd">The hWND.</param>
        ''' <param name="id">The identifier of the hotkey.
        ''' If the hWnd parameter is NULL, then the hotkey is associated with the current thread rather than with a particular window.
        ''' If a hotkey already exists with the same hWnd and id parameters.</param>
        ''' <param name="fsModifiers">The keys that must be pressed in combination with the key specified by the uVirtKey parameter
        ''' in order to generate the WM_HOTKEY message.
        ''' The fsModifiers parameter can be a combination of the following values.</param>
        ''' <param name="vk">The virtual-key code of the hotkey.</param>
        ''' <returns>
        ''' <c>true</c> if the function succeeds, otherwise <c>false</c>
        ''' </returns>
        <DllImport("user32.dll", SetLastError:=True)>
        Public Shared Function RegisterHotKey(
                      ByVal hWnd As IntPtr,
                      ByVal id As Integer,
                      ByVal fsModifiers As UInteger,
                      ByVal vk As UInteger
        ) As <MarshalAs(UnmanagedType.Bool)> Boolean
        End Function

        ''' <summary>
        ''' Unregisters a hotkey previously registered.
        ''' </summary>
        ''' <param name="hWnd">The hWND.</param>
        ''' <param name="id">The identifier of the hotkey to be unregistered.</param>
        ''' <returns>
        ''' <c>true</c> if the function succeeds, otherwise <c>false</c>
        ''' </returns>
        <DllImport("user32.dll", SetLastError:=True)>
        Public Shared Function UnregisterHotKey(
                      ByVal hWnd As IntPtr,
                      ByVal id As Integer
        ) As <MarshalAs(UnmanagedType.Bool)> Boolean
        End Function

    End Class

#End Region

#Region " Members "

    ''' <summary>
    ''' The hotkey modifier used in combination with the key.
    ''' </summary>
    <Flags>
    Public Enum HotkeyModifier As Integer

        ''' <summary>
        ''' The none
        ''' </summary>
        None = &H0

        ''' <summary>
        ''' The alt key
        ''' </summary>
        Alt = &H1

        ''' <summary>
        ''' The control key
        ''' </summary>
        Ctrl = &H2

        ''' <summary>
        ''' The shift key
        ''' </summary>
        Shift = &H4

        ''' <summary>
        ''' The win key
        ''' </summary>
        Win = &H8

    End Enum

    ''' <summary>
    ''' Event that is raised when a hotkey is pressed.
    ''' </summary>
    Public Event Press As EventHandler(Of HotKeyEventArgs)

    ''' <summary>
    ''' Stores the Press Event Arguments.
    ''' </summary>
    Protected PressEventArgs As New HotKeyEventArgs

    ''' <summary>
    ''' Event arguments for the Press event.
    ''' </summary>
    Public Class HotKeyEventArgs : Inherits EventArgs

        ''' <summary>
        ''' The identifier of the hotkey.
        ''' </summary>
        ''' <value>The identifier.</value>
        Public Property ID As Integer

        ''' <summary>
        ''' The key used for the hotkey.
        ''' </summary>
        ''' <value>The key.</value>
        Public Property Key As Keys

        ''' <summary>
        ''' The key modifier used for the hotkey.
        ''' </summary>
        ''' <value>The modifier.</value>
        Public Property Modifier As HotkeyModifier

    End Class

    ''' <summary>
    ''' Exception that is thrown when a hotkey is already registered.
    ''' </summary>
    <Serializable>
    Public Class IsRegisteredException : Inherits Exception

        ''' <summary>
        ''' Initializes a new instance of the <see cref="IsRegisteredException"/> class.
        ''' </summary>
        Sub New()
            MyBase.New("Hotkey combination is already in use.")
        End Sub

    End Class

#End Region

#Region " Constructor "

    ''' <summary>
    ''' Creates a new system-wide hotkey.
    ''' </summary>
    ''' <param name="Modifier">The keys that must be pressed in combination with the specified key.</param>
    ''' <param name="Key">The key used for the hotkey.</param>
    ''' <exception cref="IsRegisteredException"></exception>
    <DebuggerStepperBoundary()>
    Public Sub New(ByVal Modifier As HotkeyModifier, ByVal Key As Keys)

        Me.CreateHandle(New CreateParams)

        Me.PressEventArgs.ID = GetHashCode()
        Me.PressEventArgs.Key = Key
        Me.PressEventArgs.Modifier = Modifier

        If Not NativeMethods.RegisterHotKey(Me.Handle,
                                            Me.PressEventArgs.ID,
                                            Me.PressEventArgs.Modifier,
                                            Me.PressEventArgs.Key) Then

            Throw New IsRegisteredException

        End If

    End Sub

#End Region

#Region " WndProc "

    ''' <summary>
    ''' Invokes the default window procedure associated with this window.
    ''' </summary>
    ''' <param name="m">
    ''' A <see cref="T:System.Windows.Forms.Message" /> that is associated with the current Windows message.
    ''' </param>
    Protected Overrides Sub WndProc(ByRef m As Message)

        If m.Msg = 786 Then
            RaiseEvent Press(Me, Me.PressEventArgs)
        Else
            MyBase.WndProc(m)
        End If

    End Sub

#End Region

#Region " IDisposable "

    ''' <summary>
    ''' To detect redundant calls when disposing.
    ''' </summary>
    Private IsDisposed As Boolean = False

    ''' <summary>
    ''' Prevent calls to methods after disposing.
    ''' </summary>
    ''' <exception cref="System.ObjectDisposedException"></exception>
    Private Sub DisposedCheck()

        If Me.IsDisposed Then
            Throw New ObjectDisposedException(Me.GetType().FullName)
        End If

    End Sub

    ''' <summary>
    ''' Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
    ''' </summary>
    Public Sub Dispose() Implements IDisposable.Dispose
        Dispose(True)
        GC.SuppressFinalize(Me)
    End Sub

    ' IDisposable
    ''' <summary>
    ''' Releases unmanaged and - optionally - managed resources.
    ''' </summary>
    ''' <param name="IsDisposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
    Protected Overridable Sub Dispose(IsDisposing As Boolean)

        If Not Me.IsDisposed Then

            If IsDisposing Then
                NativeMethods.UnregisterHotKey(Me.Handle, Me.PressEventArgs.ID)
            End If

        End If

        Me.IsDisposed = True

    End Sub

#End Region

End Class

#End Region

最佳答案

您的类继承自 NativeWindow,及其 CreateHandle() method is virtual .这就是您收到警告的原因。

如果你确定你需要调用这个方法并且没有其他方法可以这样做,我认为你可以创建一个类来覆盖和密封它:

public class SealedNativeWindow : NativeWindow
{
    public override sealed void CreateHandle(CreateParams cp)
    {
        base.CreateHandle(CreateParams cp);
    }
}

然后让您的类继承自该类(您必须将其转换为 VB.NET)。

或者你可以只ignore the warning .

关于.net - 关于构造函数的代码分析警告,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21043492/

相关文章:

c# - 如何发出带有预加载 MethodInfo 局部变量的方法?

c# - 在 C# 函数中设置 Excel 单元格的公式

javascript - 使用 Javascript 在标签中显示列表项

继承构造函数的 C++ 可见性

c++ - 实时系统的两阶段构建

c++ - 模板化复制构造函数因特定模板化类型而失败

c# - 在 .NET 中使用 Thread.Abort() 和处理 ThreadAbortException 是否安全?

c# - 如何将自动映射器与 System.AddIn 一起使用?

.net - Visual Studio - 在设计 View 中显示属性窗口,但在代码 View 中隐藏

vb.net - 在 vb.net 中以不同用户身份运行新进程