確か:
void ValidateStuff(someArg) {
if (!validation(someArg)) {
throw new ValidationException("Whatever went wrong...", errorDetails);
}
}
そして、あなたのコード内:
ValidateStuff(someArg);
DoOtherStuff();
がP.S:生産関係のないものは、生産バイナリで終わるしないように、私は多くの場合、#if (DEBUG) [...] #else [...] #endif
とValidateStuff
に汎用コードを兼ね備えています。
警告はどうですか?
私はそのためのいくつかのトリックを使用します。あなたが本当にそれを必要とする場合にのみ、エラーオブジェクトを作成し
- を。
- 同様に、何かが失敗した場合にだけエラーのリストを作成します。
- 簡単にコーディングするために「使用」を使用してください。私は怠惰なコーダーです...これは小さなリスクですが、あなたが使い方を忘れると、あなたは困っています...しかし、私は、このリスクは「ショーと一緒に行き、最初に何か警告があったことを忘れてください」という選択肢よりも優れていると思います。
- あなたの警告のためのハンドラがあれば(例外の代わりに)、それを使ってそれを使ってください。
- エラーが発生した場合は、ロットを投げてください。さらに原因がなければ、あなたが合うようにあなたがそれを拡張することができます明らかに
...
:
public class WarningsHandler : IDisposable
{
private List<WarningErrorBase> 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<Error> FetchValidationResults()
{
var errors = this.errors;
this.errors = null;
return errors;
}
public void Warn(bool condition, Func<Warning> errorBuilder)
{
if (condition)
{
if (errors == null) { errors = new List<WarningErrorBase>(); }
errors.Add(errorBuilder());
}
}
public void Error(bool condition, Func<Error> errorBuilder)
{
if (condition)
{
if (errors == null) { errors = new List<WarningErrorBase>(); }
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
を使用することです。これにより、異なる動作で複数の結果値を返すことができます。null値は無視することができます。
まず私たちは、このためにラッパーの全体の束を必要とする:
// 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<T> : 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<Message> 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<Message> messages)
{
throw new ValidationException(this.Text);
}
}
// Other wrappers like warnings, etc.
// Wrapping IEnumerable<IResult> is useful too.
次に、我々は今、代わりに通常のタイプのIEnumerableをを返す私たちの方法を実行するために、いくつかのヘルパーメソッドが必要です。そのために、基本的に実行、アンラッピング、戻り値を処理するヘルパークラスを追加します。
public static class ExecutionEngine
{
public static T Execute<T>(this IEnumerable<IResult> method)
{
List<Message> messages = new List<Message>();
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<T> returnValue = item as Result<T>;
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
}
}
}
これをすべて整えば、コード自体はかなりシンプルになり、通常と同じように非常によく似ています。主な違いは、あなたは、単に時々、追加のラッパーで、どこでも「降伏リターン」を追加することです:
public IEnumerable<IResult> MyMethod()
{
// Delegate validation to somewhere else. You might wrap an IEnumerable<IResult> 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<int>();
tmp[2] = 2; // oopz...
// ...
yield return new Result<int>(12); // return 12;
}
唯一のものが残っているが、あなたはもうMyMethod
を呼び出すことはできませんということです。これは、実行エンジンを使用して簡単に修正できます。
この機能のさらに広い範囲は何ですか?あなたはバリデーションを持っているし、何かを行う別のクラスを持っていますか?彼らは彼らの背後に共通の目的を持っていますか? –
できません。コードを最小限に抑えるためにできることは、return文を囲む中括弧を省略することだけです。 – ThePerplexedOne
ほとんどの場合、有効な入力が期待される場合は、 'EnsureStuffValid(someArg)'に何も返さず、stuffが有効でない場合に例外をスローすることができます。 –