C#泛型与委托:一个简单的数组模板示例

本文介绍了如何在C#中利用泛型和委托创建一个二维数组模板,以提高代码复用性和效率。通过示例展示,模板使得避免了为不同数据类型重复编写代码的问题,提升了开发效率。

以下是个人项目中可能会用到的一个二维数组模板,简便高效(?)

using System;
using System.Collections.Generic;

namespace Array2DTemplate
{
    public class Array2D<Ty> where Ty : struct // 泛型约束 Ty必须struct类型
    {
        private int _row;
        private int _col;
        private Ty[,] _data;

        #region GetSet
        public Ty[,] Data
        {
            get
            {
                return _data;
            }
            set
            {
                _data = value;
            }
        }

        public int Row
        {
            get
            {
                return _row;
            }
        }

        public int Col
        {
            get
            {
                return _col;
            }
        }

        public void SetData(Ty[] buffer)
        {
            int _size = _row * _col;
            int size=buffer.Length;
            if(size<_size)
            {
                throw new Exception("Notenough size");
            }
            int k = 0;
            for (int i = 0; i < _row; ++i)
            {
                for (int j = 0; j < _col; ++j)
                {
                    _data[i, j] = buffer[k];
                    ++k;
                }
            }
        }

        #endregion GetSet

        #region Constructions
        public Array2D()
        {
            _row = 0;
            _col = 0;
            _data = null;
        }

        public Array2D(int row, int col)
        {
            if (row <= 0 || col <= 0)
            {
                throw new Exception("Dimension size must be positive!");
            }
            _row = row;
            _col = col;
            _data = new Ty[row, col];
        }

        #endregion Constructions

        #region SimpleOperations

        public Array2D<Ty> Add(Array2D<Ty> another)
        {
            int row = another.Row;
            int col = another.Col;
            if (row != _row || col != _col)
            {
                throw new Exception("Size must be the same!");
            }
            Array2D<Ty> result = new Array2D<Ty>(row, col);
            Ty[,] A = _data;
            Ty[,] B = another.Data;
            Ty[,] R = result.Data;
            for (int i = 0; i < row; ++i)
            {
                for (int j = 0; j < col; ++j)
                {
                    R[i, j] = BaseArithmetic.Add<Ty>(A[i, j], B[i, j]);
                }
            }

            return result;
        }

        public Array2D<Ty> Sub(Array2D<Ty> another)
        {
            int row = another.Row;
            int col = another.Col;
            if (row != _row || col != _col)
            {
                throw new Exception("Size must be the same!");
            }
            Array2D<Ty> result = new Array2D<Ty>(row, col);
            Ty[,] A = _data;
            Ty[,] B = another.Data;
            Ty[,] R = result.Data;
            for (int i = 0; i < row; ++i)
            {
                for (int j = 0; j < col; ++j)
                {
                    R[i, j] = BaseArithmetic.Sub<Ty>(A[i, j], B[i, j]);
                }
            }

            return result;
        }

        public Array2D<Ty> Mul(Array2D<Ty> another)
        {
            int row = another.Row;
            int col = another.Col;
            if (row != _row || col != _col)
            {
                throw new Exception("Size must be the same!");
            }
            Array2D<Ty> result = new Array2D<Ty>(row, col);
            Ty[,] A = _data;
            Ty[,] B = another.Data;
            Ty[,] R = result.Data;
            for (int i = 0; i < row; ++i)
            {
                for (int j = 0; j < col; ++j)
                {
                    R[i, j] = BaseArithmetic.Mul<Ty>(A[i, j], B[i, j]);
                }
            }

            return result;
        }

        public Array2D<Ty> Div(Array2D<Ty> another)
        {
            int row = another.Row;
            int col = another.Col;
            if (row != _row || col != _col)
            {
                throw new Exception("Size must be the same!");
            }
            Array2D<Ty> result = new Array2D<Ty>(row, col);
            Ty[,] A = _data;
            Ty[,] B = another.Data;
            Ty[,] R = result.Data;
            for (int i = 0; i < row; ++i)
            {
                for (int j = 0; j < col; ++j)
                {
                    R[i, j] = BaseArithmetic.Div<Ty>(A[i, j], B[i, j]);
                }
            }

            return result;
        }

        public void FindMaxMin(out Ty max, out Ty min)
        {
            int ret = 0;
            Ty value;
            max = _data[0, 0];
            min = _data[0, 0];
            for (int i = 0; i < _row; ++i)
            {
                for (int j = 0; j < _col; ++j)
                {
                    value = _data[i, j];
                    ret = BaseComparator<Ty>.Instance.Compare(value, max);
                    if (ret >= 0) max = value;
                    else
                    {
                        ret = BaseComparator<Ty>.Instance.Compare(value, min);
                        if (ret < 0) min = value;
                    }
                }
            }

            if (BaseComparator<Ty>.Instance.Compare(max, min) == 0)
            {
                throw new Exception("Max = Min");
            }
        }

        #endregion SimpleOperations

        #region OverloadedOperations

        public static Array2D<Ty> operator +(Array2D<Ty> a, Array2D<Ty> b)
        {
            return a.Add(b);
        }

        public static Array2D<Ty> operator -(Array2D<Ty> a, Array2D<Ty> b)
        {
            return a.Sub(b);
        }

        public static Array2D<Ty> operator *(Array2D<Ty> a, Array2D<Ty> b)
        {
            return a.Mul(b);
        }

        public static Array2D<Ty> operator /(Array2D<Ty> a, Array2D<Ty> b)
        {
            return a.Div(b);
        }

        #endregion OverloadedOperations
    }

    public static class BaseArithmetic
    {
        private static string GetTypeString<Ty>(Ty t) where Ty : struct
        {
            string ts = typeof(Ty).ToString();
            return ts.Substring(ts.LastIndexOf('.') + 1);
        }

        #region BasicOperations
        public static Ty Add<Ty>(Ty a, Ty b) where Ty : struct
        {
            string str = GetTypeString<Ty>(a);
            switch (str)
            {
                case "Int16":
                case "Int32":
                    int result1 = Convert.ToInt32(a) + Convert.ToInt32(b);
                    return (Ty)(Convert.ChangeType(result1, typeof(Ty)));
                case "Byte":
                case "UInt16":
                case "UInt32":
                    uint result2 = Convert.ToUInt32(a) + Convert.ToUInt32(b);
                    return (Ty)(Convert.ChangeType(result2, typeof(Ty)));
                case "Single":
                case "Double":
                    double result3 = Convert.ToDouble(a) + Convert.ToDouble(b);
                    return (Ty)(Convert.ChangeType(result3, typeof(Ty)));
                default:
                    return (Ty)(new object());
            }
        }

        public static Ty Sub<Ty>(Ty a, Ty b) where Ty : struct
        {
            string str = GetTypeString<Ty>(a);
            switch (str)
            {
                case "Int16":
                case "Int32":
                    int result1 = Convert.ToInt32(a) - Convert.ToInt32(b);
                    return (Ty)(Convert.ChangeType(result1, typeof(Ty)));
                case "Byte":
                case "UInt16":
                case "UInt32":
                    uint result2 = Convert.ToUInt32(a) - Convert.ToUInt32(b);
                    return (Ty)(Convert.ChangeType(result2, typeof(Ty)));
                case "Single":
                case "Double":
                    double result3 = Convert.ToDouble(a) - Convert.ToDouble(b);
                    return (Ty)(Convert.ChangeType(result3, typeof(Ty)));
                default:
                    return (Ty)(new object());
            }
        }

        public static Ty Mul<Ty>(Ty a, Ty b) where Ty : struct
        {
            string str = GetTypeString<Ty>(a);
            switch (str)
            {
                case "Int16":
                case "Int32":
                    int result1 = Convert.ToInt32(a) * Convert.ToInt32(b);
                    return (Ty)(Convert.ChangeType(result1, typeof(Ty)));
                case "Byte":
                case "UInt16":
                case "UInt32":
                    uint result2 = Convert.ToUInt32(a) * Convert.ToUInt32(b);
                    return (Ty)(Convert.ChangeType(result2, typeof(Ty)));
                case "Single":
                case "Double":
                    double result3 = Convert.ToDouble(a) * Convert.ToDouble(b);
                    return (Ty)(Convert.ChangeType(result3, typeof(Ty)));
                default:
                    return (Ty)(new object());
            }
        }

        public static Ty Div<Ty>(Ty a, Ty b) where Ty : struct
        {
            string str = GetTypeString<Ty>(a);
            switch (str)
            {
                case "Int16":
                case "Int32":
                    int ib = Convert.ToInt32(b);
                    if (ib == 0) throw new DivideByZeroException();
                    int result1 = Convert.ToInt32(a) / ib;
                    return (Ty)(Convert.ChangeType(result1, typeof(Ty)));
                case "Byte":
                case "UInt16":
                case "UInt32":
                    uint ub = Convert.ToUInt32(b);
                    if (ub == 0) throw new DivideByZeroException();
                    uint result2 = Convert.ToUInt32(a) / ub;
                    return (Ty)(Convert.ChangeType(result2, typeof(Ty)));
                case "Single":
                case "Double":
                    double db = Convert.ToDouble(b);
                    if (Math.Abs(db) < Double.Epsilon) throw new DivideByZeroException();
                    double result3 = Convert.ToDouble(a) / db;
                    return (Ty)(Convert.ChangeType(result3, typeof(Ty)));
                default:
                    return (Ty)(new object());
            }
        }

        #endregion BasicOperations
    }

    public static class BaseConvertor
    {
        public static Array2D<byte> ToByteArray<Ty>(Array2D<Ty> src, out double scale, out double offset) where Ty : struct
        {
            int row = src.Row;
            int col = src.Col;
            Array2D<byte> dst = new Array2D<byte>(row, col);

            byte[,] dstData = dst.Data;
            Ty[,] srcData = src.Data;

            Ty max, min;
            src.FindMaxMin(out max, out min);
            scale = Convert.ToDouble(BaseArithmetic.Sub(max, min)) / 255;
            offset = Convert.ToDouble(min);
            for (int i = 0; i < row; ++i)
            {
                for (int j = 0; j < col; ++j)
                {
                    dstData[i, j] = (byte)(Convert.ToDouble(BaseArithmetic.Sub(srcData[i, j], min)) / scale + 0.5);
                }
            }

            return dst;
        }
    }

    public class BaseComparator<Ty>
    {
        Comparison<Ty> _comparison;                  //比较委托
        static readonly Dictionary<Type, Delegate> _map = new Dictionary<Type, Delegate>();
        //实现单例
        static readonly BaseComparator<Ty> _instance = new BaseComparator<Ty>();
        private BaseComparator() { }
        public static BaseComparator<Ty> Instance
        {
            get
            {
                System.Diagnostics.Debug.Assert(_map.ContainsKey(typeof(Ty)));
                //强转为具体的比较委托
                _instance._comparison = (Comparison<Ty>)_map[typeof(Ty)];
                return _instance;
            }
        }
        //情态构造,初始化
        static BaseComparator()
        {
            //基础类型比较器
            Type t = typeof(Ty);
            if (t == typeof(Byte))
            {
                Comparison<Byte> cmp_Byte = delegate(Byte t1, Byte t2) { return t1 > t2 ? 1 : (t1 == t2 ? 0 : -1); };
                _map.Add(typeof(Byte), (Delegate)cmp_Byte);
            }
            else if(t==typeof(UInt16))
            {
                Comparison<UInt16> cmp_UInt16 = delegate(UInt16 t1, UInt16 t2) { return t1 > t2 ? 1 : (t1 == t2 ? 0 : -1); };
                _map.Add(typeof(UInt16), (Delegate)cmp_UInt16);
            }
            else if (t == typeof(Int16))
            {
                Comparison<Int16> cmp_Int16 = delegate(Int16 t1, Int16 t2) { return t1 > t2 ? 1 : (t1 == t2 ? 0 : -1); };
                _map.Add(typeof(Int16), (Delegate)cmp_Int16);
            }
            else if(t==typeof(UInt32))
            {
                Comparison<UInt32> cmp_UInt32 = delegate(UInt32 t1, UInt32 t2) { return t1 > t2 ? 1 : (t1 == t2 ? 0 : -1); };
                _map.Add(typeof(UInt32), (Delegate)cmp_UInt32);
            }
            else if(t==typeof(Int32))
            {
                Comparison<Int32> cmp_Int32 = delegate(Int32 t1, Int32 t2) { return t1 > t2 ? 1 : (t1 == t2 ? 0 : -1); };
                _map.Add(typeof(Int32), (Delegate)cmp_Int32);
            }
            else if (t == typeof(Single))
            {
                Comparison<Single> cmp_Single = delegate(Single t1, Single t2) { return t1 > t2 ? 1 : (t1 == t2 ? 0 : -1); };
                _map.Add(typeof(Single), (Delegate)cmp_Single);
            }
            else if (t == typeof(Double))
            {
                Comparison<Double> cmp_Double = delegate(Double t1, Double t2) { return t1 > t2 ? 1 : (t1 == t2 ? 0 : -1); };
                _map.Add(typeof(Double), (Delegate)cmp_Double);
            }
            else
            {
                throw new Exception("Unsupported type!");
            }
        }
        //注册自定义比较
        public static void Register<NewTy>(Comparison<NewTy> comparison)
        {
            System.Diagnostics.Debug.Assert(_map.ContainsKey(typeof(NewTy)) == false);

            _map.Add(typeof(NewTy), (Delegate)comparison);
        }
        //比较函数,以后用来实现IComparator用
        public int Compare(Ty t1, Ty t2)
        {
            System.Diagnostics.Debug.Assert(_comparison != null);

            return _comparison(t1, t2);
        }
    }
}


使用示例

            Array2D<int> ia = new Array2D<int>(800, 800);
            for (int i = 0; i < 800; ++i)
            {
                for (int j = 0; j < 800; ++j)
                {
                    ia.Data[i, j] = ((400 - i) * (400 - j)) % 400;
                }
            }
            double scale,offset;
            Array2D<byte> ba = BaseConvertor.ToByteArray(ia, out scale,out offset);


生成的二维数组转换成灰度图像如下



瞬间科技感了~~~

还可以这样

            Array2D<int> ia = new Array2D<int>(800, 800);
            Array2D<int> ib = new Array2D<int>(800, 800);
            Random rnd = new Random();
            for (int i = 0; i < 800; ++i)
            {
                for (int j = 0; j < 800; ++j)
                {
                    ia.Data[i, j] = ((400 - i) * (400 - j)) % 400;  //同上
                    ib.Data[i, j] =rnd.Next(-200,200); //随机噪声
                }
            }
            Array2D<int> ic = ia - ib; // 重载了基本运算符(+,-,*,/) 用起来很方便了

添加噪声后的数组ic,现将其转换为byte数组
Array2D<byte> bc=BaseConvertor.ToByteArray(ic,scale,offset);
将bc转换为灰度图如下


更加科技感了~~~

这个模板会用到个人的项目中,更多内容不便公开,待项目完成之后再公布。

如果不使用模板,那么针对每一种数据类型都要分别编写代码,

大量的重复工作,效率很低,因此建议使用泛型(Generics)和委托(Delegates).


LOG@ 2014/08/15 11:36 Fri. BJ


点此领取楼主 (本文全原创,转载请注明出处 http://blog.youkuaiyun.com/fengyhack)


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值