您的位置:首页 > 编程语言 > C#

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

2014-08-15 11:31 246 查看
以下是个人项目中可能会用到的一个二维数组模板,简便高效(?)

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.csdn.net/fengyhack)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  泛型