Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/308.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/107.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何正确地取消订阅活动_C# - Fatal编程技术网

C# 如何正确地取消订阅活动

C# 如何正确地取消订阅活动,c#,C#,如何才能正确地取消订阅事件,并确保现在未调用调用的方法 我的问题是这种代码: public class MyClassWithEvent { public event EventHandler MyEvent; public int Field; } public class MyMainClass { private MyClassWithEvent myClass; public void Start() { myClass.MyE

如何才能正确地取消订阅事件,并确保现在未调用调用的方法

我的问题是这种代码:

public class MyClassWithEvent
{
    public event EventHandler MyEvent;
    public int Field;
}

public class MyMainClass
{
    private MyClassWithEvent myClass;

    public void Start()
    {
        myClass.MyEvent += new EventHandler(doSomething);
    }

    public void Stop()
    {
        myClass.MyEvent -= new EventHandler(doSomething);
        myClass = null;
    }

    private void doSomething()
    {
        myClass.Field = 42;
    }
}
如果在执行
doSomething
时调用了
myClass=null
,则指令
myClass.Field=42
会引发错误,因为myClass为null

在设置
myClass=null
之前,如何确保没有执行
doSomething

编辑:

其他例子:

public void Stop()
{
    myClass.MyEvent -= new EventHandler(doSomething);

    // Can I add a function here to be sure that doSomething is not running ?

    myClass.Field = 101;
}
在这种情况下,我不确定
myClass.Field
是42还是101

Edit2:

显然我的问题不像我想的那么简单。我将解释我的确切情况

我的代码是:

public class MyMainClass
{
    object camera;//can be type uEye.Camera or DirectShowCamera
    bool isRunning = false;

    public void Start()
    {
        if (camera is uEye.Camera)
        {
            camera.EventFrame += new EventHandler(NewFrameArrived);
        }
        else if (camera is DirectShowCamera)
        {
            //other init
        }
        isRunning = true;
    }

    public void Stop()
    {
        if (camera is uEye.Camera)
        {
            camera.EventFrame -= new EventHandler(NewFrameArrived);
            camera.exit;
        }
        else if (camera is DirectShowCamera)
        {
            //other stop
        }
        isRunning = false;
    }

    public void ChangeCamera(object new camera)
    {
        if (isRunning)
            Stop()
        camera = new camera();
    }

    void NewFrameArrived(object sender, EventArgs e)
    {
        uEye.Camera Camera = sender as uEye.Camera;
        Int32 s32MemID;
        Camera.Memory.GetActive(out s32MemID);

        lock (_frameCameralocker)
        {
            if (_frameCamera != null)
                _frameCamera.Dispose();
            _frameCamera = null;
            Camera.Memory.ToBitmap(s32MemID, out _frameCamera);
        }

        Dispatcher.Invoke(new Action(() =>
        {
            lock (_frameCameralocker)
            {
                var bitmapData = _frameCamera.LockBits(
                    new System.Drawing.Rectangle(0, 0, _frameCamera.Width, _frameCamera.Height),
                    System.Drawing.Imaging.ImageLockMode.ReadOnly, _frameCamera.PixelFormat);

                if (_frameCamera.PixelFormat == System.Drawing.Imaging.PixelFormat.Format8bppIndexed)
                {
                    DeviceSource = System.Windows.Media.Imaging.BitmapSource.Create(
                                                        bitmapData.Width, bitmapData.Height, 96, 96, System.Windows.Media.PixelFormats.Gray8, null,
                                                        bitmapData.Scan0, bitmapData.Stride * bitmapData.Height, bitmapData.Stride);
                }

                _frameCamera.UnlockBits(bitmapData);

                if (OnNewBitmapReady != null)
                    OnNewBitmapReady(this, null);
            }
        }));
    }
}
有时,当我将摄像头从uEye更改为directshow时,我在
DeviceSource=System.Windows.Media.Imaging.BitmapSource.Create
(方法
NewFrameArrived
)中遇到了AccessViolationException,因为我试图从退出的摄像头创建BitmapSource

myClass.Field = 42;

也许这对你有用

这样做的目的是使用锁来确保您不会在(几乎)同一时间两次使用同一资源:

public class MyClassWithEvent
{
    public event EventHandler MyEvent;
    public int Field;
}

public class MyMainClass
{
    private MyClassWithEvent myClass;
    private object mylock;

    public void Start()
    {
        myClass.MyEvent += new EventHandler(doSomething);
    }

    public void Stop()
    {
        myClass.MyEvent -= new EventHandler(doSomething);
        Monitor.Enter(mylock); //If somebody else already took the lock, we will wait here
        myClass = null;
        Monitor.Exit(mylock); //We release the lock, so others can access it
    }

    private void doSomething()
    {
        Monitor.Enter(mylock);
        if myClass != null
        {
            myClass.Field = 42;
        }
        Monitor.Exit(mylock);
    }
}
编辑

根据评论,使用()会更好:


根据您更新的问题,您只需将
Stop()
操作锁定在与
Dispatcher.Invoke相同的锁中即可

public void Stop()
{
    lock(_frameCameralocker)
    {
        if (camera is uEye.Camera)
        {
            camera.EventFrame -= new EventHandler(NewFrameArrived);
            camera.exit;
        }
        else if (camera is DirectShowCamera)
        {
            //other stop
        }
        isRunning = false;
    }
}
这将确保所有
NewFrameArrived
调用在创建新相机之前已完成或尚未启动。然后在dispatcher内部检查您是否正在运行,以防在
Stop()
调用启动和完成之前帧排队

    Dispatcher.Invoke(new Action(() =>
    {
        lock (_frameCameralocker)
        {
            if(!isRunning)
                return;

            var bitmapData = _frameCamera.LockBits(
                new System.Drawing.Rectangle(0, 0, _frameCamera.Width, _frameCamera.Height),
                System.Drawing.Imaging.ImageLockMode.ReadOnly, _frameCamera.PixelFormat);

            if (_frameCamera.PixelFormat == System.Drawing.Imaging.PixelFormat.Format8bppIndexed)
            {
                DeviceSource = System.Windows.Media.Imaging.BitmapSource.Create(
                                                    bitmapData.Width, bitmapData.Height, 96, 96, System.Windows.Media.PixelFormats.Gray8, null,
                                                    bitmapData.Scan0, bitmapData.Stride * bitmapData.Height, bitmapData.Stride);
            }

            _frameCamera.UnlockBits(bitmapData);

            if (OnNewBitmapReady != null)
                OnNewBitmapReady(this, null);
        }
    }));

在赋值之前检查它是否为null?我的示例可能太简单了,我可以使用其他case而不使用
myClass
。我将编辑我的问题以显示其他大小写。@仅检查一次不会解决问题,因为我的类可以在检查后和使用前分配为null。这就是为什么我建议在本地值中保留对myClass的引用。您还没有显示引发事件的代码或发生这种情况的位置/原因。除非这是程序的异步或并行部分,否则不应在语句之间引发事件。这意味着在第一段代码中引发事件应该发生在
停止之前
,或者之后它不会调用
doSomething
。在上一个示例中,在将
字段
设置为101.@A.pissict之后,在执行某个稍后的代码之前不应引发该事件。在发生
Stop()
锁定之前,您仍然可能遇到调度程序排队的问题。您只需在dispatcher中输入一个
IsRunning
复选框,查看我的答案。我用另一个案例编辑了我的问题,您的解决方案将不适用于第二个案例。我正在寻找一种同步机制在这种情况下,请看一下ReaderWriterLockSlim,我认为它对您很有用,因为您正在尝试控制写操作。MSDN link无需使用
监视器
只需使用
锁定
。使用锁定或尝试最终锁定对象。我使用了自己的锁定(请参见edit2)而不是
监视器
,我现在没有异常
public void Stop()
{
    lock(_frameCameralocker)
    {
        if (camera is uEye.Camera)
        {
            camera.EventFrame -= new EventHandler(NewFrameArrived);
            camera.exit;
        }
        else if (camera is DirectShowCamera)
        {
            //other stop
        }
        isRunning = false;
    }
}
    Dispatcher.Invoke(new Action(() =>
    {
        lock (_frameCameralocker)
        {
            if(!isRunning)
                return;

            var bitmapData = _frameCamera.LockBits(
                new System.Drawing.Rectangle(0, 0, _frameCamera.Width, _frameCamera.Height),
                System.Drawing.Imaging.ImageLockMode.ReadOnly, _frameCamera.PixelFormat);

            if (_frameCamera.PixelFormat == System.Drawing.Imaging.PixelFormat.Format8bppIndexed)
            {
                DeviceSource = System.Windows.Media.Imaging.BitmapSource.Create(
                                                    bitmapData.Width, bitmapData.Height, 96, 96, System.Windows.Media.PixelFormats.Gray8, null,
                                                    bitmapData.Scan0, bitmapData.Stride * bitmapData.Height, bitmapData.Stride);
            }

            _frameCamera.UnlockBits(bitmapData);

            if (OnNewBitmapReady != null)
                OnNewBitmapReady(this, null);
        }
    }));