使用异常通知委托未设置-设计不良

本文关键字:设置 不良 异常 通知 | 更新日期: 2023-09-27 18:01:17

我创建了一个文档类,用于下载并读取其中的文本。聪明之处在于,它只在需要时下载并读取文档中的文本。通过使用Text属性,它将尝试读取文档,如果它还没有被下载,它将下载然后读取它。

它很好。然而,我注意到我使用异常导致一些时髦的代码。见下文.

文档类

public delegate byte[] DownloadBinaryDelegate(IDocument document);
public delegate string TextReaderDelegate(IDocument document);
public class Document
{
        public DownloadBinaryDelegate DownloadBinaryDelegate { private get; set; }
        public TextReaderDelegate TextReaderDelegate { private get; set; }
        private bool _binaryIsSet;
        private byte[] _binary;
        public byte[] Binary
        {
            get 
            {
                if (_binaryIsSet)
                    return _binary;
                if (DownloadBinaryDelegate == null)
                    throw new NullReferenceException("No delegate attached to DownloadBinaryDelegate.");
                Binary = DownloadBinaryDelegate(this);
                DownloadBinaryDelegate = null; // unhock delegate as it's no longer needed.
                return _binary;
            }
            set
            {
                if (_binaryIsSet) 
                    return;
                _binary = value;
                _binaryIsSet = true;
            }
        }
        private bool _textIsSet;
        private string _text;
        public string Text
        {
            get
            {
                if (_textIsSet)
                    return _text;
                if (TextReaderDelegate == null)
                    throw new NullReferenceException("No delegate attached to TextReaderDelegate.");
                Text = TextReaderDelegate(this); // this delegate will call Binary and return the translated text.
                TextReaderDelegate = null; // unhock delegate as it's no longer needed.
                return _text;
            }
            set
            {
                if (_textIsSet)
                    return;
                _text = value;
                _textIsSet = true;
            }
        }

我一开始写的东西。

if (document.Text == null) // text is not set
{
    if (document.Binary == null) // binary has not been downloaded
        document.DownloadBinaryDelegate = Util.DownloadDocument;
    document.TextReaderDelegate = Util.ReadDocument;
}

完全忘记了Text属性会抛出异常。所以我必须写这样的东西,这是一个有点奇怪的代码。

// check if text has already been read and set
try
{
    var isTextSet = document.Text == null;
}
catch (NullReferenceException)
{
    document.DownloadBinaryDelegate = Util.DownloadDocument;
    document.TextReaderDelegate = Util.ReadDocument;
}

希望你能明白我的意思。

所以我的问题是,这是一个糟糕的设计吗?你会怎么做?请记住,我仍然喜欢当前的功能。

使用异常通知委托未设置-设计不良

延迟初始化已经融入。net框架。我建议使用Lazy<T>重新实现您的类。

要回答您的具体问题,听起来您的类将始终需要二进制和文本委托,所以我将它们设置为构造函数的必需参数。

我无法使用Lazy,因为我正在使用delegate(this),这是不允许的。

所以我最终使用了这里的好答案:当属性不能为空时使用什么异常类型?

public class Document
{
    private DownloadBinaryDelegate _downloadBinaryDelegate;
    public void SetDownloadBinaryDelegate(DownloadBinaryDelegate downloadBinary)
    {
        if (downloadBinary == null)
            throw new ArgumentNullException("downloadBinary");
        _downloadBinaryDelegate = downloadBinary;
    }
    private TextReaderDelegate _textReaderDelegate;
    public void SetTextReaderDelegate(TextReaderDelegate readerDelegate)
    {
        if (readerDelegate == null)
            throw new ArgumentNullException("readerDelegate");
        _textReaderDelegate = readerDelegate;
    }
    private bool _binaryIsSet;
    private byte[] _bytes;
    public void SetBinary(byte[] bytes, bool forceOverwrite = false)
    {
        if (_binaryIsSet && !forceOverwrite)
            return;
        _bytes = bytes;
        _binaryIsSet = true;
    }
    public byte[] GetBinary()
    {
        if (_binaryIsSet)
            return _bytes;
        if (_downloadBinaryDelegate == null)
            throw new InvalidOperationException("No delegate attached to DownloadBinaryDelegate. Use SetDownloadBinaryDelegate.");
        SetBinary(_downloadBinaryDelegate(this));
        _downloadBinaryDelegate = null; // unhock delegate as it's no longer needed.
        return _bytes;
    }
    public bool TryGetBinary(out byte[] bytes)
    {
        if (_binaryIsSet)
        {
            bytes = _bytes;
            return true;
        }
        if (_downloadBinaryDelegate != null)
        {
            bytes = GetBinary(); // is this legit?
            return true;
        }
        bytes = null;
        return false;
    }
    private bool _textIsSet;
    private string _text;
    public void SetText(string text, bool forceOverwrite = false)
    {
        if (_textIsSet && !forceOverwrite)
            return;
        _text = text;
        _textIsSet = true;
    }
    public string GetText()
    {
        if (_textIsSet)
            return _text;
        if (_textReaderDelegate == null)
            throw new InvalidOperationException("No delegate attached to TextReaderDelegate. Use SetTextReaderDelegate.");
        SetText(_textReaderDelegate(this)); // this delegate will call Binary and return the read text.
        _textReaderDelegate = null; // unhock delegate as it's no longer needed.
        return _text;
    }
    public bool TryGetText(out string text)
    {
        byte[] bytes;
        if (!TryGetBinary(out bytes))
        {
            text = null;
            return false;
        }
        if (_textIsSet)
        {
            text = _text;
            return true;
        }
        if (_textReaderDelegate != null)
        {
            text = GetText(); // is this legit?
            return true;
        }
        text = null;
        return false;
    }
}