我有一个Visual Studio 2008 C#.NET 3.5类,它提供对本机库的访问。该库有一个Register方法,允许用户指定将在某个事件上激活的回调。我在下面提供了一个C#实现:
internal class MyLibHandle : SafeHandleZeroOrMinusOneIsInvalid { /*...*/ }
internal static class NativeMethods
{
public delegate void OnSomeEventDelegate (FOO foo, IntPtr user);
[DllImport("MyLib.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.U1)]
public static extern bool MyLib_Register(MyLibHandle handle, OnSomeEventDelegate callback, IntPtr user);
}
public class MyWrappedLib : IDisposable
{
private MyLibHandle handle_;
private event EventHandler<OnSomeEventArgs> some_event_int_;
public event EventHandler<OnSomeEventArgs> SomeEvent
{
add
{
if (some_event_int_ == null)
{
if (!NativeMethods.MyLib_Register(handle_, ReceivedSomeEvent, IntPtr.Zero))
throw new Win32Exception(Marshal.GetLastWin32Error());
}
some_event_int_ += value;
}
remove
{
some_event_int_ -= value;
if (some_event_int_ == null)
{
if (!NativeMethods.MyLib_DeRegister(handle_, -1))
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
}
private void ReceivedSomeEvent(FOO foo, IntPtr user)
{
OnSomeEvent(new OnSomeEventArgs() { foo = foo });
}
protected virtual void OnBeacon(OnSomeEventArgs args)
{
EventHandler<OnSomeEventArgs> evt = some_event_int_;
if (evt != null)
evt(this, args);
}
}
这样可行,但我收到了一些不祥的声音警告
warning : CA1065 : Microsoft.Design : 'MyWrappedLib.SomeEvent.add(EventHandler<OnSomeEventArgs>)' creates an exception of type 'Win32Exception', an exception type that should not be raised in this type of method.
warning : CA2122 : Microsoft.Security : 'MyWrappedLib.SomeEvent.add(EventHandler<OnSomeEventArgs>)' calls into 'Marshal.GetLastWin32Error()' which has a LinkDemand. By making this call, 'Marshal.GetLastWin32Error()' is indirectly exposed to user code.
处理这种情况的推荐方法是什么?我应该创建一个方法来处理事件订阅而不是传统的添加;去掉;存取?
由于
答案 0 :(得分:1)
对于事件访问器,允许以下异常类型:
System.InvalidOperationException 以及所有衍生品(包括 的 System.ObjectDisposedException 强>)
System.NotSupportedException 及所有衍生产品
ArgumentException 和衍生物
为什么native方法返回false? 是否与某些外部条件有关, 或者是传递无效参数的结果?
所以我将Win32Exception包装为InvalidOperationException的内部, 或者ArgumentException,具体取决于您的情况。
第二次警告(CA2122)是关于安全的 - 它警告Marshal.GetLastWin32Error执行安全检查, 而你的代码没有。此安全检查仅执行一次, 在第一次通话。之后的所有呼叫都未验证访问权限, 出于性能原因。所以从理论上讲,第一次通话可以通过 受信任的用户,并且不会限制所有其他呼叫。
您需要使用以下属性装饰您的事件处理程序:
[SecurityPermission(SecurityAction.InheritanceDemand,Flags = SecurityPermissionFlag.UnmanagedCode)]
(它将检查代码是否有权调用托管代码) 如果您的申请中不担心安全问题,请禁止或警告此警告。
this question中详细说明了详细信息。