0

我正在尝试创建一个小的 rx 异常处理代码块,我希望在其中获得在特定情况下显示的相同异常。

实际用例是我有一个按钮,它尝试从剪贴板获取数据,用户可能有权访问,也可能无权访问,这将导致引发 SecurityException。

还有可能发生其他一些异常,我也想处理(尽管向用户显示不同的错误消息)。

流本身也有可能出现问题,我想在订阅者的 OnError 方法中处理。

这是我到目前为止所拥有的(请注意,我使用 TextBox 来模拟​​剪贴板上的文本,并使用复选框来模拟是否应该引发 SecurityException)

private Subject<bool> simulatedPasteCommandSubject = new Subject<bool>();
private readonly CompositeDisposable disposables = new CompositeDisposable();

public Form1()
{
    InitializeComponent();
    WireUpSimulatedPasteCommandSubject();
}


private Func<IObservable<string>> ObserverableFactory
{
    get
    {
        return () =>
        {
            return Observable.Defer(() =>
            {
                return simulatedPasteCommandSubject
                    .Select(_ => this.GetText())
                    .Where(x => !string.IsNullOrWhiteSpace(x))
                    .TrySelect<string, string>(this.TrySelectClipboardData);
            });
        };
    }
}


private void WireUpSimulatedPasteCommandSubject()
{
    var clipboardStream = ObserverableFactory();

    this.disposables.Add(clipboardStream
        .Catch((SecurityException ex) =>
        {
            this.ShowError("SecurityException");
            return ObserverableFactory();
        })
        .Catch((Exception ex) =>
        {
            this.ShowError("Exception");
            return ObserverableFactory();
        })
        .Do(data => LogData(data))
        .Subscribe(
            data => this.ImportTheClipboardData(data),
            ex => this.ShowError("Something very bad happened")));
}

private void ImportTheClipboardData(string data)
{
    MessageBox.Show(string.Format("Importing Clipboard data\r\n {0}", data));
}

private string GetText()
{
    if (chkShouldThrow.Checked)
        throw new SecurityException("SecurityException");

    // simulate text coming from Clipboard
    return textBox1.Text; 
}

private void button1_Click(object sender, EventArgs e)
{
    simulatedPasteCommandSubject.OnNext(true);
}

private bool TrySelectClipboardData(string dataIn, out string dataOut)
{
    dataOut = string.Join("", dataIn.Reverse());
    return true;
}

private void LogData(string data)
{
    string dataLog = string.Format("Data : {0}", data);
    Debug.WriteLine(dataLog);
}

private void ShowError(string ex)
{
    string error = string.Format("Error : {0}", ex);
    MessageBox.Show(error);
}

抱歉,列表太大了。问题是,如果我在 TextBox 中键入一些文本(以模拟剪贴板)然后单击按钮(这是模拟用户会做什么,这使得剪贴板流产生 (OnNext)),我得到了我所期望的。在这种情况下,一个简单的反转字符串。

但是,如果我单击应该模拟引发 SecurityException 的 CheckBox,然后单击按钮(这是模拟用户将执行的操作,这使得剪贴板流产生(OnNext)),我确实捕获了 SecurityException,并看到记录。到目前为止一切都很好

当我尝试使用 CheckBox 再次单击该按钮时,问题就出现了,该 CheckBox 应该模拟引发的 SecurityException 仍然处于选中状态。然后我得到以下

“例外”

然后,当我尝试使用应模拟引发 SecurityException 的 CheckBox 再次单击该按钮时,仍处于选中状态。然后我得到以下

“发生了非常糟糕的事情”

当我期望看到的是“SecurityException”每次都被捕获时,因为这是第一次。

我有一种感觉,这与返回的相同流有关,该流以前在“SecurityException”的捕获中

4

2 回答 2

1

如果我正确理解了您的代码,您希望吞下所有 SecurityExcetions 并将序列透明地重新连接到用户。即,如果用户尝试多次访问剪贴板,他们会多次收到错误消息。

如果是这种情况,您的问题在于您缺少循环。您最初从工厂获得序列。如果这个序列出错,那么你会得到第二个序列。但是,如果第二个序列出错,您将无法理解。

我认为您想要做的是捕获预期的异常,显示消息框,然后继续出现错误的序列。然后,这将允许您记录错误并利用Retry()操作员。

也许这样的事情会有所帮助

clipboardStream
    .Catch((SecurityException ex) =>
    {
        this.ShowError("SecurityException");
        return Observable.Throw<string>(ex);
    })
    .Catch((Exception ex) =>
    {
        this.ShowError("Exception");
        return Observable.Throw<string>(ex);
    })
    .Do(data => LogData(data))
    .Retry()
    .Subscribe(
        data => this.ImportTheClipboardData(data),
        ex => this.ShowError("Wont get here (I dont think!)"));

尝试 2

clipboardStream
    .Do(data => LogData(data))
    .Catch((SecurityException ex) =>
    {
        this.ShowError("SecurityException");
        return Observable.Throw<string>(ex);
    })
    .Retry()
    .Catch((Exception ex) =>
    {
        this.ShowError("Exception");
        return Observable.Throw<string>(ex);
    })
    .Retry()
    .Subscribe(
        data => this.ImportTheClipboardData(data),
        ex => this.ShowError("Wont get here (I dont think!)"));
于 2013-06-18T09:12:52.820 回答
0

好的,所以 Lee Campbell Attempt 2 给了我我想要的东西。这是完全重新设计的解决方案(感谢李)

public partial class Form1 : Form
{
    private Subject<bool> simulatedPasteCommandSubject = new Subject<bool>();
    private readonly CompositeDisposable disposables = new CompositeDisposable();

    public Form1()
    {
        InitializeComponent();
        WireUpSimulatedPasteCommandSubject();
    }


    private Func<IObservable<string>> ObserverableFactory
    {
        get
        {
            return () =>
            {
                return Observable.Defer(() =>
                {
                    return simulatedPasteCommandSubject
                        .Select(_ => this.GetText())
                        .Where(x => !string.IsNullOrWhiteSpace(x))
                        .TrySelect<string, string>(this.TrySelectClipboardData);
                });
            };
        }
    }


    private void WireUpSimulatedPasteCommandSubject()
    {
        var clipboardStream = ObserverableFactory();
        this.disposables.Add(clipboardStream
            .Do(data => LogData(data))
            .Catch((SecurityException ex) =>
            {
                this.ShowError("SecurityException");
                return Observable.Throw<string>(ex);
            })
            .Retry()
            .Catch((Exception ex) =>
            {
                this.ShowError("Exception");
                return Observable.Throw<string>(ex);
            })
            .Retry()
            .Subscribe(
                data => this.ImportTheClipboardData(data),
                ex => this.ShowError("Wont get here (I dont think!)")));
    }

    private void ImportTheClipboardData(string data)
    {
        MessageBox.Show(string.Format("Importing Clipboard data\r\n {0}", data));
    }

    private string GetText()
    {
        if (chkShouldThrow.Checked)
            throw new SecurityException("SecurityException");

        // simulate text coming from Clipboard
        return textBox1.Text;
    }

    private void button1_Click(object sender, EventArgs e)
    {
        simulatedPasteCommandSubject.OnNext(true);
    }

    private bool TrySelectClipboardData(string dataIn, out string dataOut)
    {
        dataOut = string.Join("", dataIn.Reverse());
        return true;
    }

    private void LogData(string data)
    {
        string dataLog = string.Format("Data : {0}", data);
        Debug.WriteLine(dataLog);
    }

    private void ShowError(string ex)
    {
        string error = string.Format("Error : {0}", ex);
        MessageBox.Show(error);
    }
}
于 2013-06-19T08:16:13.900 回答