/// <summary> /// Pushes a new context message into this stack. /// </summary> /// <param name="message">The new context message.</param> /// <returns> /// An <see cref="IDisposable"/> that can be used to clean up the context stack. /// </returns> /// <remarks> /// <para> /// Pushes a new context onto this stack. An <see cref="IDisposable"/> /// is returned that can be used to clean up this stack. This /// can be easily combined with the <c>using</c> keyword to scope the /// context. /// </para> /// </remarks> /// <example>Simple example of using the <c>Push</c> method with the <c>using</c> keyword. /// <code lang="C#"> /// using(log4net.LogicalThreadContext.Stacks["NDC"].Push("Stack_Message")) /// { /// log.Warn("This should have an ThreadContext Stack message"); /// } /// </code> /// </example> public IDisposable Push(string message) { // do modifications on a copy Stack stack = new Stack(new Stack(m_stack)); stack.Push(new StackFrame(message, (stack.Count > 0) ? (StackFrame)stack.Peek() : null)); LogicalThreadContextStack contextStack = new LogicalThreadContextStack(m_propertyKey, m_registerNew); contextStack.m_stack = stack; m_registerNew(m_propertyKey, contextStack); return(new AutoPopStackFrame(contextStack, stack.Count - 1)); }
/// <summary> /// Removes the top context from this stack. /// </summary> /// <returns>The message in the context that was removed from the top of this stack.</returns> /// <remarks> /// <para> /// Remove the top context from this stack, and return /// it to the caller. If this stack is empty then an /// empty string (not <see langword="null"/>) is returned. /// </para> /// </remarks> public string Pop() { // copy current stack Stack stack = new Stack(new Stack(m_stack)); string result = ""; if (stack.Count > 0) { result = ((StackFrame)(stack.Pop())).Message; } LogicalThreadContextStack ltcs = new LogicalThreadContextStack(m_propertyKey, m_registerNew); ltcs.m_stack = stack; m_registerNew(m_propertyKey, ltcs); return(result); }
/// <summary> /// Returns the stack to the correct depth. /// </summary> /// <remarks> /// <para> /// Returns the stack to the correct depth. /// </para> /// </remarks> public void Dispose() { if (m_frameDepth >= 0 && m_logicalThreadContextStack.m_stack != null) { Stack stack = new Stack(new Stack(m_logicalThreadContextStack.m_stack)); while (stack.Count > m_frameDepth) { stack.Pop(); } LogicalThreadContextStack ltcs = new LogicalThreadContextStack(m_logicalThreadContextStack.m_propertyKey, m_logicalThreadContextStack.m_registerNew); ltcs.m_stack = stack; // 每次 Pop() 后,用新的栈,将原来的替换掉 m_logicalThreadContextStack.m_registerNew(m_logicalThreadContextStack.m_propertyKey, ltcs); } }
/// <summary> /// 线程栈索引器 /// 只读,如果键没找到,会自动添加一个键,然后返回一个空栈 /// </summary> /// <param name="key"></param> /// <returns></returns> public LogicalThreadContextStack this[string key] { get { LogicalThreadContextStack stack = null; object propertyValue = m_properties[key]; if (propertyValue == null) { // Stack does not exist, create stack = new LogicalThreadContextStack(key, new TwoArgAction(registerNew)); m_properties[key] = stack; } else { // Look for existing stack stack = propertyValue as LogicalThreadContextStack; if (stack == null) { // Property is not set to a stack! string propertyValueString = SystemInfo.NullText; try { propertyValueString = propertyValue.ToString(); } catch { } LogLog.Error(declaringType, "ThreadContextStacks: Request for stack named [" + key + "] failed because a property with the same name exists which is a [" + propertyValue.GetType().Name + "] with value [" + propertyValueString + "]"); stack = new LogicalThreadContextStack(key, new TwoArgAction(registerNew)); } } return(stack); } }
/// <summary> /// Constructor /// </summary> /// <param name="logicalThreadContextStack">The internal stack used by the ThreadContextStack.</param> /// <param name="frameDepth">The depth to return the stack to when this object is disposed.</param> /// <remarks> /// <para> /// Initializes a new instance of the <see cref="AutoPopStackFrame" /> class with /// the specified stack and return depth. /// </para> /// </remarks> internal AutoPopStackFrame(LogicalThreadContextStack logicalThreadContextStack, int frameDepth) { m_frameDepth = frameDepth; m_logicalThreadContextStack = logicalThreadContextStack; }
/// <summary> /// 在属性字典中,添加一个新的键值对或者将旧值覆盖掉 /// </summary> /// <param name="stackName"></param> /// <param name="stack"></param> private void registerNew(string stackName, LogicalThreadContextStack stack) { m_properties[stackName] = stack; }