作者:我爱看电视OK | 来源:互联网 | 2023-02-06 01:03
1> atlaste..:
当然:
void ValidateStuff(someArg) {
if (!validation(someArg)) {
throw new ValidationException("Whatever went wrong...", errorDetails);
}
}
在你的代码中:
ValidateStuff(someArg);
DoOtherStuff();
PS:我经常在结合通用的代码ValidateStuff
与#if (DEBUG) [...] #else [...] #endif
,使生产不相关的东西并不在生产二进制文件结束.
怎么警告?
我用了一些技巧:
仅在您确实需要时才构建错误对象.
同样,只有在出现故障时才构建错误列表.
利用'使用'轻松编码.我是一个懒惰的程序员......虽然风险很小; 如果你忘记使用,你就会遇到麻烦......不过,我认为这种风险比"让我们继续演出并忘记首先发出警告"的选择更好.
如果你有一个更好的警告处理程序(所以:而不是异常),使用它并完成它.
如果发生错误,请抛出该批次.
显然你可以按照你认为合适的方式扩展它......
没有进一步到期:
public class WarningsHandler : IDisposable
{
private List errors = null;
// Default handler. Remember to use 'using', or otherwise you'll end up
// with pain and suffering!
public void Dispose()
{
var errors = FetchValidationResults();
if (errors != null && errors.Count > 0)
{
throw new ValidationException(errors);
}
}
// Handler if you have a better idea than using an Exception
public IEnumerable FetchValidationResults()
{
var errors = this.errors;
this.errors = null;
return errors;
}
public void Warn(bool condition, Func errorBuilder)
{
if (condition)
{
if (errors == null) { errors = new List(); }
errors.Add(errorBuilder());
}
}
public void Error(bool condition, Func errorBuilder)
{
if (condition)
{
if (errors == null) { errors = new List(); }
errors.Add(errorBuilder());
throw new ValidationException(FetchValidationResults());
}
}
}
如何使用它?
void MyThing()
{
using (var handler = new WarningsHandler())
{
handler.Error(foo == null, "Foo must have a value");
handler.Warn(foo.Count > 2, () => new Warning("You should have less than 2 foo's present.");
// etc.
}
}
好的,还有一个技巧.:-)
混合不同错误消息的最后一种方法是使用yield return
.这使您可以返回具有不同行为的多个结果值.空值可以忽略不计.
首先,我们需要一大堆包装器:
// We need some base interface that we can use for return values
public interface IResult { }
// We have to wrap normal return values
public class Result : IResult
{
public Result(T result) { this.Value = result; }
public T Value { get; private set; }
}
// A few classes for messages, errors, warnings, ...
public class Message : IResult
{
public Message(string format, params object[] args)
{
this.Text = string.Format(format, args);
}
public string Text { get; private set; }
internal virtual void Handle(List messages)
{
messages.Add(this);
}
}
public class Error : Message
{
public Error(Exception ex) :
base("Uncaught exception: {0}", ex.Message)
{ }
public Error(string format, params object[] args) :
base(format, args)
{ }
internal override void Handle(List messages)
{
throw new ValidationException(this.Text);
}
}
// Other wrappers like warnings, etc.
// Wrapping IEnumerable is useful too.
接下来,我们需要一些辅助方法来执行我们现在返回IEnumerable而不是普通类型的方法.为此,我添加了一个辅助类,它基本上处理执行,解包和返回值.
public static class ExecutionEngine
{
public static T Execute(this IEnumerable method)
{
List messages = new List();
try
{
foreach (var item in method)
{
// yield return null is ignored here:
if (item != null)
{
// Handle validation results, messages, etc
Message msg = item as Message;
if (msg != null)
{
msg.Handle(messages);
}
Result returnValue = item as Result;
if (returnValue != null)
{
return returnValue.Value;
}
// handle other things, error if something's wrong
}
}
throw new Exception("Method finished without a return value.");
}
catch (ValidationException)
{
// TODO: handle messages?
throw;
}
catch (Exception ex)
{
// TODO: handle messages?
var error = new Error(ex);
error.Handle(messages);
throw; // unreachable because Error throws. This is to make sure it all compiles
}
}
}
一旦我们按顺序完成所有这些,代码本身就变得非常简单,就像你通常会做的很像.主要区别在于您只需在任何地方添加"yield return",有时会使用额外的包装器:
public IEnumerable MyMethod()
{
// Delegate validation to somewhere else. You might wrap an IEnumerable here:
yield return ValidateStuff(someArg);
// Information messages, etc
yield return new Message("Hello world!");
// You might end up with an Exception you didn't expect...
var tmp = new List();
tmp[2] = 2; // oopz...
// ...
yield return new Result(12); // return 12;
}
唯一剩下的就是你不能再打电话MyMethod
了.使用执行引擎可以很容易地解决这个问题:
int result = MyMethod().Execute();
这将OP指向正确的方向,即使用异常而不是"返回错误".