支持类型过滤的枚举器

    在VB和C#中,要枚举一个列表中的若干的对象,很容易使用 foreach 结构,抛开性能的话题,foreach 结构简单直观,使用方便。深受广大VB和C#程序员的喜爱。
在C#中,若要实现一个可用于foreach结构的枚举器必须实现 System.Collections.IEnumerable ,然后使用 "foreach( 成员类型 obj in 枚举器变量 )" 的语法结构来使用该枚举器。
    但有些时候,枚举器有时枚举器返回的对象类型可能是变化的,为此我们在foreach循环中需要进行类型转换和判断。

    比如我们对以下XML文档的根节点的子XML元素进行枚举

<members>
    文本内容
    
<!-- 注释1 -->
    
<aa>aaaaaaaaa</aa>
    
<!-- 注释2 -->
    
<bb>bbbbbbbbbbb</bb>
    文本内容
    
<!-- 注释3 -->
    
<cc>cccccccc</cc>
    
<!-- 注释4 -->
    
<!-- 注释5 -->
    
<!-- 注释6 -->
    
<dd>eeeeeeeeeee</dd>
    
<!-- 注释7 -->
    
<devdoc>ffffffffffffff</devdoc>
    
<devdoc>aa</devdoc>
    
<devdoc>文本内容</devdoc>
</members>

    很显然,这个XML文档的根节点下有一些不是XML元素的成员。比如文本和注释。此时遍历时需要判断当前节点是否是XML元素类型。为此被迫多些上几行代码,类似的代码写多了那就烦了。

    为了避免这种麻烦,在此提出支持类型过滤的枚举器的概念,这种枚举器是其他枚举器的包装,它能从其他枚举器获得对象,并返回指定类型的当前对象,这样我们使用支持类型过滤的枚举器时,只需要在开始遍历的时候指明所需的对象类型,进行循环遍历的时候就不必再进行类型判断,
使用类型过滤的枚举器,能让我们编写代码时避免一些类型判断的处理,简单可靠,写代码的时候比较舒服。

    此时有人会提出性能问题。在此根据我个人的编程经验,大部分情况下,性能基本大部分是决定于算法,算法设计得好,性能就不会差。各种技术上的包装可能降低性能,但属于细节,无伤大雅。但在少数情况下,算法的具体实现过程就能很大的影响性能,比如若foreach需要完成很大规模的遍历工作量,则此时是否使用这种支持类型过滤的遍历器则需要认真判断了。

    以下是演示代码

using System;

namespace EnumFilter
{
    /// 
<summary>
    /// Class1 的摘要说明。
    /// 
</summary>
    class Class1
    {
        /// 
<summary>
        /// 带类型过滤的枚举器对象的测试代码
        /// 
</summary>
        /// 
<remarks>编制 袁永福( http://www.xdesigner.cn ) 2007-3-20</remarks>
        [STAThread]
        static void Main(string[] args)
        {
            System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
            doc.LoadXml(@"
<members>
    文本内容
    
<!-- 注释1 -->
    
<aa>aaaaaaaaa</aa>
    
<!-- 注释2 -->
    
<bb>bbbbbbbbbbb</bb>
    文本内容
    
<!-- 注释3 -->
    
<cc>cccccccc</cc>
    
<!-- 注释4 -->
    
<!-- 注释5 -->
    
<!-- 注释6 -->
    
<dd>eeeeeeeeeee</dd>
    
<!-- 注释7 -->
    
<devdoc>ffffffffffffff</devdoc>
    
<devdoc>aa</devdoc>
    
<devdoc>文本内容</devdoc>
</members>");
        
            // 未使用类型过滤的枚举器
            // 需要在循环中进行类型的转换和判断
            foreach( System.Xml.XmlNode node in doc.DocumentElement.ChildNodes )
            {
                // 若不加上下行遍历则会发生转换无效错误
                System.Xml.XmlElement element = node as System.Xml.XmlElement ;
                if( element != null )
                {
                    System.Console.WriteLine( element.Name + "  #  " + element.InnerText );
                }
            }
            System.Console.WriteLine("######################");
            // 使用类型过滤的枚举器
            // 不需要在循环中进行类型的转换和判断
            foreach( System.Xml.XmlElement element in 
                new TypeFilterEnum( doc.DocumentElement.ChildNodes , typeof( System.Xml.XmlElement )))
            {
                System.Console.WriteLine( element.Name + "  #  " + element.InnerText );
            }
            System.Console.WriteLine("按回车键退出");
            System.Console.ReadLine();
        }

        /// 
<summary>
        /// 带类型过滤的枚举器对象
        /// 
</summary>
        /// 
<remarks>编制 袁永福( http://www.xdesigner.cn ) 2007-3-20</remarks>
        public class TypeFilterEnum : System.Collections.IEnumerable
        {
            /// 
<summary>
            /// 初始化对象
            /// 
</summary>
            /// 
<param name="e">枚举器</param>
            /// 
<param name="t">符合的类型</param>
            public TypeFilterEnum( System.Collections.IEnumerator e , System.Type t )
            {
                this.myEnum = e ;
                this.myMatchType = t ;
            }

            /// 
<summary>
            /// 初始化对象
            /// 
</summary>
            /// 
<param name="e">枚举器</param>
            /// 
<param name="t">符合的类型</param>
            public TypeFilterEnum( System.Collections.IEnumerable e , System.Type t )
            {
                this.myEnum = e.GetEnumerator();
                this.myMatchType = t ;
            }

            /// 
<summary>
            /// 返回枚举器对象
            /// 
</summary>
            /// 
<returns>枚举器对象</returns>
            public System.Collections.IEnumerator GetEnumerator()
            {
                MyEnumerator e = new MyEnumerator();
                e.myEnum = myEnum ;
                e.myMatchType = myMatchType ;
                return e ;
            }

            #region 内部代码 **************************************************

            private System.Collections.IEnumerator myEnum = null;
            private System.Type myMatchType = null;

            private class MyEnumerator : System.Collections.IEnumerator
            {
                internal System.Collections.IEnumerator myEnum = null;
                internal System.Type myMatchType = null;

                public void Reset()
                {
                    myEnum.Reset();
                }

                public object Current
                {
                    get
                    {
                        return myEnum.Current ;
                    }
                }

                public bool MoveNext()
                {
                    while( myEnum.MoveNext())
                    {
                        object o = myEnum.Current ;
                        System.Type t = o.GetType();
                        if( t.Equals( myMatchType ) || t.IsSubclassOf( t ))
                            return true ;
                    }
                    return false;
                }
            }

            #endregion 
        }//public class TypeFilterEnum : System.Collections.IEnumerable
    }
}


袁永福( http://www.xdesigner.cn ) 2007-3-20

原文地址:https://www.cnblogs.com/xdesigner/p/681126.html