C# 使用异常通知委托未设置-设计错误?
我创建了一个文档类,可以下载和读取其中的文本。聪明的是,它只在需要时下载和读取文档中的文本。通过使用Text属性,它将尝试读取文档,如果文档尚未下载,它将下载文档,然后读取 非常好。然而,我注意到我对异常的使用导致了一些古怪的代码。见下文 文档类C# 使用异常通知委托未设置-设计错误?,c#,exception,delegates,class-design,C#,Exception,Delegates,Class Design,我创建了一个文档类,可以下载和读取其中的文本。聪明的是,它只在需要时下载和读取文档中的文本。通过使用Text属性,它将尝试读取文档,如果文档尚未下载,它将下载文档,然后读取 非常好。然而,我注意到我对异常的使用导致了一些古怪的代码。见下文 文档类 public delegate byte[] DownloadBinaryDelegate(IDocument document); public delegate string TextReaderDelegate(IDocument documen
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 framework中。我建议您使用重新实现您的类
为了回答您的特定问题,听起来您的类总是需要二进制和文本委托,因此我会将它们作为构造函数的必需参数。我无法使用Lazy,因为我使用的是委托(this),这是不允许的 因此,我最终使用了下面这个很好的答案:
您不应该从属性中抛出异常。检查答案:从类似的问题。哈哈,我感觉有什么不对劲。我会读一读的,谢谢。我找到了一个可以接受的答案。属于codereview.stackexchange.Com不知道那件事。下一次我会知道的。这门课比所展示的内容还多,我只选了基本部分:)。我来看看Lazy@Sn在这种情况下,您的类可能违反了单一责任原则。也许值得将这个类的这一部分划分成一个新的类。我很确定它符合单一责任原则,因为它与文档有关。它是文件名和其他特定于域的文档元数据。:)我也不能通过ctor设置它,因为创建文档的地方不知道如何下载它。@Snæbjørn看,对我来说,这听起来像是违反了规定。下载文档和存储文档的元数据是两个完全不同的职责。我希望能够将下载代码与文档测试完全分开进行单元测试。但最终,这只是一个指导原则——没有什么可以让人失眠的;)
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;
}
}