通过类库中的事件引发异常

时间:2017-09-06 01:31:34

标签: c# events exception-handling

通过订阅包含异常的事件,让消费者选择处理异常是不是一种坏习惯吗?如果是这样,如果我这样做,我可能遇到什么问题?下面的代码就是一个例子。

我设想将此模式与视图模型一起使用。视图模型将订阅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;
    }
}

1 个答案:

答案 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))));
    }
}