代码之家  ›  专栏  ›  技术社区  ›  user7116

在库中分析期间引发错误/警告的模式

  •  4
  • user7116  · 技术社区  · 15 年前

    // Rough outline of the current code
    public abstract class ModelReader : IDisposable
    {
        public abstract Model Read();
    
        public event EventHandler<MessageAvailableEventArgs> MessageAvailable;
    
        protected virtual void RaiseError(string message)
        {
            var handler = this.MessageAvailable;
            if (handler != null)
            {
                handler(this, new MessageAvailaibleEventArgs(
                    TraceEventType.Error, message);
            }
        }
    }
    

    编辑 Read 使用异常时,所有致命错误的例程都将快速失败。消息被记录到用户端的潜在多个源,因此任何模式都应该避免限制潜在源的数量。

    6 回复  |  直到 15 年前
        1
  •  3
  •   Simon Mourier    14 年前

    我可以给你一个真实的例子。这个 Html Agility Pack

        public abstract class ModelReader
        {
            private List<ParseError> _errors = new List<ParseError>();
            private bool _throwOnError;
    
            public ModelReader()
               :this(true)
            {
            }
    
            public ModelReader(bool throwOnError)
            {
               _throwOnError = throwOnError;
            }
    
            // use AddError in implementation when an error is detected
            public abstract Model Read();
    
            public virtual IEnumerable<ParseError> Errors
            {
               get {return _errors;}
            }
    
            protected virtual void AddError(ParseError error)
            {
               if (_throwOnError) // fail fast?
                  throw new ParseException(error);
    
               _errors.Add(error);
            }
        }
    
        public class ParseError
        {
            public ParseError(...)
            {
            }
    
            public ParseErrorCode Code { get; private set; }
            public int Line { get; private set; }
            public int LinePosition { get; private set; }
            public string Reason { get; private set; }
            public string SourceText { get; private set; }
            public int StreamPosition { get; private set; }
        }
    
        public enum ParseErrorCode
        {
           InvalidSyntax,
           ClosingQuoteNotFound,
           ... whatever...
        }
    
        public class ParseException: Exception
        {
            ...
        }
    

    如果库调用方想要动态事件,您仍然可以添加事件。

        2
  •  2
  •   Alois Kraus    14 年前

    似乎需要一个可组合的验证器,用户可以在其中插入自己的逻辑,将特定的非致命错误标记为致命、警告或信息性消息。抛出异常不符合要求,因为如果另一部分希望将其转换为警告但希望继续解析,则您已经离开了该方法。这听起来很像Windows中用于结构化异常处理的两遍异常处理模型。 基本上就像

    1. 当在pass中检测到问题时,将询问所有处理程序(尚未抛出exption!)哪个人想处理这个错误。第一个说“是”的将成为决定做什么的实际处理者。

    这种两次传递模型的优点是,在第一次传递期间,会询问所有处理程序,但您仍然可以继续解析您离开的位置。还没有国家被摧毁。

    在C#中,您当然可以更自由地将其转换为更灵活的错误转换和报告管道,在这里您可以转换为严格的读取器,例如所有错误警告。

    windowsdk库有时很难使用,因为那里的工程师优化得更多,减少了服务调用。他们会向你抛出一个Win32错误代码或HResult,你必须弄清楚你违反了什么原则(内存对齐,缓冲区大小,交叉线程,…)。

        3
  •  1
  •   Andrew Bezzub    15 年前

    我认为事件订阅模式是可以的。但是你可以考虑接口。这可能会给你更多的灵活性。像这样的:

    public interface IMessageHandler
    {
        void HandleMessage(object sender, MessageAvailaibleEventArgs eventArgs);
    }    
    
    public abstract class ModelReader : IDisposable
    {
        private readonly IMessageHandler handler; // Should be initialized somewhere, e.g. in constructor
    
        public abstract Model Read();
    
        public event EventHandler<MessageAvailableEventArgs> MessageAvailable;
    
        protected virtual void RaiseError(string message)
        {
            MessageAvailaibleEventArgs eventArgs =
                new MessageAvailaibleEventArgs(TraceEventType.Error, message);
            this.handler.HandleMessage(this, eventArgs);
        }
    }
    

    因此,现在您可以使用消息处理程序的任何实现,对于exmaple事件订阅1:

    public class EventMessageHandler : IMessageHandler
    {
        public event EventHandler<MessageAvailaibleEventArgs> MessageAvailable;
    
        public void HandleMessage(object sender, MessageAvailaibleEventArgs eventArgs)
        {
            var handler = this.MessageAvailable;
            if (handler != null)
            {
                handler(this, new MessageAvailaibleEventArgs(
                    TraceEventType.Error, message);
            }
        }
    }
    
        4
  •  1
  •   Huperniketes    14 年前

    您当前的方法不是最干净的模型,因为它有两种相互矛盾的执行方式,pull(读取输入)和push(处理错误回调),这意味着您的阅读器和它的客户端都需要更多的状态管理来提供一个连贯的整体。

    我建议您避免使用类似XmlReader的接口,并使用visitor模式将输入数据和错误推送到客户机应用程序。

        5
  •  0
  •   kay.one    15 年前

    如果严格地说这是为了跟踪和检测,我要么使用您的模式,要么使用text writer模式,在这种模式下,使用者将传入一个文本编写器,而您将向其中写入跟踪信息,唯一的问题是您只能有一个外部订阅服务器。但这会产生一个稍微干净的代码。

     public TextWriter Log { get; set; }
    
     private void WriteToLog(string Message)
     {
        if (Log != null) Log.WriteLine(message);
     }
    
        6
  •  0
  •   deepee1    14 年前

        void Read(Func<string, bool> WarningHandler)
        {
            bool cancel = false;
            if (HasAWarning)
                cancel = WarningHandler("Warning!");
        }
    

    当然,你可以在Func委托中做任何你想做的事情,比如将警告分发给多个源。但是,当与事件模型结合使用时,您可以用一种通用的方式处理所有警告(可能像日志记录器一样),并将Func用于单独的专用操作和控制流(如果需要)。

    推荐文章