[.NET] CastingEnumerable

[.NET] : CastingEnumerable


前言 :

寫程式難免,會遇到要使用自訂函式來作物件陣列轉型。
寫了一個物件來做這個動作,跟大家分享。


說明 :

這個物件的特點為:
1. 使用到才轉型。不會在記憶體,建立整個轉型後的陣列副本。
2. 可在轉型時加入參數。


使用範例 :

namespace CLK.Collections.ConsoleApplication
{
    public class User
    {
        public string LastName = string.Empty;

        public string FirstName = string.Empty;
    }

    public class Data
    {
        public string DisplayName = string.Empty;
    }

    class Program
    {
        static void Main(string[] args)
        {            
            User[] userArray = new User[2];

            userArray[0] = new User();
            userArray[0].LastName = "Chou";
            userArray[0].FirstName = "Clark";

            userArray[1] = new User();
            userArray[1].LastName = "AAAA";
            userArray[1].FirstName = "BBBBB";


            IEnumerable<Data> dataList = CreateDataList(userArray, "★★★★★");
            foreach (Data data in dataList)
            {
                Console.WriteLine(data.DisplayName);
            }
            Console.WriteLine("");
            

            Console.WriteLine("End");
            Console.ReadLine();
        }

        static IEnumerable<Data> CreateDataList(IEnumerable<User> userList, string decorator)
        {
            return new CastingEnumerable<Data, User>(userList, delegate(User user) { return CreateData(user, decorator); });
        }

        static Data CreateData(User user, string decorator)
        {
            Data data = new Data();
            data.DisplayName = decorator + user.LastName + "." + user.FirstName + decorator;
            return data;
        }
    }  
}

程式碼 :

namespace CLK.Collections
{
    public class CastingEnumerable<TResult, TSource> : IEnumerable<TResult>
    {
        //Properties 
        private readonly IEnumerable<TSource> _sourceEnumerable;

        private CastingEnumerableDelegate<TResult, TSource> _enumerableDelegate;


        // Construction 
        public CastingEnumerable(IEnumerable<TSource> sourceEnumerable, CastingEnumerableDelegate<TResult, TSource> enumerableDelegate)
        {
            #region Require

            if (sourceEnumerable == null) throw new ArgumentNullException();
            if (enumerableDelegate == null) throw new ArgumentNullException();

            #endregion
            _sourceEnumerable = sourceEnumerable;
            _enumerableDelegate = enumerableDelegate;
        }


        // Member 
        public IEnumerator<TResult> GetEnumerator()
        {
            return new CastingEnumerator<TResult, TSource>(_sourceEnumerable.GetEnumerator(), _enumerableDelegate);
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator();
        }
    }
}

namespace CLK.Collections
{
    public class CastingEnumerator<TResult, TSource> : IEnumerator<TResult>
    {
        //Properties 
        private readonly IEnumerator<TSource> _sourceEnumerator;

        private readonly CastingEnumerableDelegate<TResult, TSource> _enumerableDelegate;

        private TResult _currentResult = default(TResult);


        // Construction 
        public CastingEnumerator(IEnumerator<TSource> sourceEnumerator, CastingEnumerableDelegate<TResult, TSource> enumerableDelegate)
        {
            #region Require

            if (sourceEnumerator == null) throw new ArgumentNullException();
            if (enumerableDelegate == null) throw new ArgumentNullException();

            #endregion
            _sourceEnumerator = sourceEnumerator;
            _enumerableDelegate = enumerableDelegate;
        }

        public virtual void Dispose()
        {
            _sourceEnumerator.Dispose();
            _currentResult = default(TResult);
        }


        // Member  
        public TResult Current
        {
            get
            {
                return _currentResult;
            }
        }

        object System.Collections.IEnumerator.Current
        {
            get
            {
                return this.Current;
            }
        }

        public bool MoveNext()
        {
            if (_sourceEnumerator.MoveNext() == true)
            {
                _currentResult = _enumerableDelegate(_sourceEnumerator.Current);
                return true;
            }
            return false;
        }

        public void Reset()
        {
            _sourceEnumerator.Reset();
            _currentResult = default(TResult);
        }
    }
}

public delegate TResult CastingEnumerableDelegate<TResult, TSource>(TSource source);

相關資料 :

http://stackoverflow.com/questions/504729/how-do-i-cast-a-listt-effectively
http://msdn.microsoft.com/zh-tw/library/0yw3tz5k.aspx

期許自己
能以更簡潔的文字與程式碼,傳達出程式設計背後的精神。
真正做到「以形寫神」的境界。