2

我制作了一个文档类,可以下载并阅读其中的文本。聪明的是,它仅在需要时或在需要时才下载和读取文档中的文本。通过使用 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;
}

我希望你能明白我的意思。

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

4

2 回答 2

2

延迟初始化已经融入 .NET 框架。我建议使用Lazy<T>.

要回答您的具体问题,听起来您的类将始终需要 Binary 和 Text 委托,因此我会将它们设为构造函数的必需参数。

于 2013-02-27T11:01:13.837 回答
0

我无法使用 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;
    }
}
于 2013-02-27T18:59:25.113 回答