通过订阅包含异常的事件,让消费者选择处理异常是不是一种坏习惯吗?如果是这样,如果我这样做,我可能遇到什么问题?下面的代码就是一个例子。
我设想将此模式与视图模型一起使用。视图模型将订阅ExceptionRaised事件并将异常传递给日志记录类。我不想将日志记录类注入StatisticsCalculations类。
public class StatisticalCalculations
{
public event EventHandler<Exception> ExceptionReceived;
public double GetStandardDeviation(IEnumerable<double> values)
{
double standardDeviation = double.NaN;
try
{
double average = values.Average();
double sum = values.Sum(value => Math.Pow(value - average, 2));
standardDeviation = Math.Sqrt((sum) / (values.Count() - 1));
}
catch (Exception ex)
{
ExceptionReceived?.Invoke(this, ex);
}
return standardDeviation;
}
}
答案 0 :(得分:-1)
使用这样的事件会将异常与您正在调用的实际方法调用断开连接。我认为最好为此使用Exception monad。
你的课应该是这样的:
public class StatisticalCalculations
{
public Exceptional<double> GetStandardDeviation(IEnumerable<double> values)
{
try
{
double standardDeviation = double.NaN;
//Perform calculation
return standardDeviation.ToExceptional();
}
catch (Exception ex)
{
return new Exceptional<double>(ex);
}
}
}
您的调用函数可以解压缩Exceptional<double>
以查看它是否有值或是否有错误。
您需要支持的课程是:
public class Exceptional<T>
{
public bool HasException { get; private set; }
public Exception Exception { get; private set; }
public T Value { get; private set; }
public Exceptional(T value)
{
HasException = false;
Value = value;
}
public Exceptional(Exception exception)
{
HasException = true;
Exception = exception;
}
public Exceptional(Func<T> func)
{
try
{
this.Value = func();
this.HasException = false;
}
catch (Exception exc)
{
this.Exception = exc;
this.HasException = true;
}
}
public override string ToString()
{
return this.HasException
? Exception.GetType().Name
: (this.Value != null
? this.Value.ToString()
: "null");
}
}
public static class ExceptionalEx
{
public static Exceptional<T> ToExceptional<T>(this T value)
{
return new Exceptional<T>(value);
}
public static Exceptional<T> ToExceptional<T>(this Func<T> func)
{
return new Exceptional<T>(func);
}
public static Exceptional<U> SelectMany<T, U>(this Exceptional<T> value, Func<T, Exceptional<U>> k)
{
return (value.HasException)
? new Exceptional<U>(value.Exception)
: k(value.Value);
}
public static Exceptional<V> SelectMany<T, U, V>(this Exceptional<T> value, Func<T, Exceptional<U>> k, Func<T, U, V> m)
{
return value.SelectMany(t => k(t).SelectMany(u => new Exceptional<V>(() => m(t, u))));
}
}