有关构造函数的代码分析警告

时间:2014-01-10 11:43:32

标签: .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不要调用可覆盖的方法   构造函数的GlobalHotkey.New(GlobalHotkey.HotkeyModifier,Keys)'   包含一个调用链,导致调用虚方法   由班级定义。检查以下调用堆栈是否有意外   后果:

     

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

PS:第213行是:

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

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

  

更新

进入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
  

更新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

2 个答案:

答案 0 :(得分:4)

您的班级继承自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

答案 1 :(得分:2)

CreateHandle是虚拟的,你自己的任何子类都可以覆盖它,使得对象构造不受控制。有关示例,请参阅:the documentation

VB相当于CodeCaster的解决方案(这是正确的)来密封方法

Public NotOverridable Overrides Sub _
                         CreateHandle(cp As System.Windows.Forms.CreateParams)
    MyBase.CreateHandle(cp)
End Sub