如果有一个需求,用户输入数据类型和操作符号的字符串,你需要根据这些字符串来分析出用户想要的结果。
比如用户输入的是:"int","123","-","int","111",如果是这样的字符串,那么你应该读作int类型的123-111,结果为12。
又比如用户输入的是:"datetime","2011-07-03","<","datetime","2010-05-01",这样的字符串是用户想进行datetime类型的数据的大小比较,结果为false。
我的设计思路是:
首先我要能识别出用户输入的这些类型,比如上面举例的int和datetime。这里有两种办法,第一我可以枚举返回系统定义的int和datetime,第二我可以枚举我自己定义的int和datetime,我的想法是枚举我自定义的,因为我还需要解析操作符号,系统定义的数据类型没办法去解析我自己定义的操作符号。
其次我要能识别出操作符号,以及知道这些操作符号应该进行一个什么样的运算。设想还是使用枚举来完成。
C#中一个很好用的函数是Convert.ChangeType,它允许用户将某个类型转换成其他类型。但是如何你需要转换的对象不是继承自IConvertible接口,那么系统会抛出异常,转换就失败了。
1.定义一个接口
public interface IUserDataType
{
bool isGreater(IUserDataType obj1);
bool isSmaller(IUserDataType obj1);
bool isMoreOrEqual(IUserDataType obj1);
bool isLessOrEqual(IUserDataType obj1);
bool isEqual(IUserDataType obj1);
bool isUnEqual(IUserDataType obj1);
}
这个接口中可以定义一些你所需要的操作符号的函数,为的就是枚举对应到操作符的识别。
2.定义一个父类,这个类继承自上面的接口
public abstract class UserDataType : IUserDataType
{
public abstract bool isGreater(IUserDataType obj1);
public abstract bool isSmaller(IUserDataType obj1);
public abstract bool isMoreOrEqual(IUserDataType obj1);
public abstract bool isLessOrEqual(IUserDataType obj1);
public abstract bool isEqual(IUserDataType obj1);
public abstract bool isUnEqual(IUserDataType obj1);
public static Type getType(string typeName)
{
switch (typeName)
{
case "int":
return typeof(UserInt);
case "datetime":
return typeof(UserDateTime);
case "decimal":
return typeof(UserDecimal);
case "string":
return typeof(UserString);
}
return null;
}
}
注意一点,操作符号对应的函数使用abstract描述。另外,这个类中有一个static的函数是为了枚举得到所需要的type。
3.定义一个int类型,继承自父类
public class UserInt : UserDataType
{
private int int_value;
public UserInt()
{
int_value = 0;
}
public UserInt(int mvalue)
{
int_value = mvalue;
}
public string toString()
{
return int_value.ToString();
}
public static bool operator ==(UserInt value1, UserInt value2)
{
return value1.int_value == value2.int_value;
}
public static bool operator !=(UserInt value1, UserInt value2)
{
return value1.int_value != value2.int_value;
}
public static bool operator >(UserInt value1, UserInt value2)
{
return value1.int_value > value2.int_value;
}
public static bool operator <(UserInt value1, UserInt value2)
{
return value1.int_value < value2.int_value;
}
public static bool operator >=(UserInt value1, UserInt value2)
{
return value1.int_value >= value2.int_value;
}
public static bool operator <=(UserInt value1, UserInt value2)
{
return value1.int_value <= value2.int_value;
}
public override bool isGreater(IUserDataType obj1)
{
if (!obj1.GetType().Equals(typeof(UserInt))) return false;
return this > (obj1 as UserInt);
}
public override bool isSmaller(IUserDataType obj1)
{
if (!obj1.GetType().Equals(typeof(UserInt))) return false;
return this < (obj1 as UserInt);
}
public override bool isEqual(IUserDataType obj1)
{
if (!obj1.GetType().Equals(typeof(UserInt))) return false;
return this == (obj1 as UserInt);
}
public override bool isUnEqual(IUserDataType obj1)
{
if (!obj1.GetType().Equals(typeof(UserInt))) return false;
return this != (obj1 as UserInt);
}
public override bool isMoreOrEqual(IUserDataType obj1)
{
if (!obj1.GetType().Equals(typeof(UserInt))) return false;
return this >= (obj1 as UserInt);
}
public override bool isLessOrEqual(IUserDataType obj1)
{
if (!obj1.GetType().Equals(typeof(UserInt))) return false;
return this <= (obj1 as UserInt);
}
}
这个userint类就是一个很普通的自定义类型,它重载了操作符号,并且这些重载过的操作符号被用于接口中的函数。
4.最重要的一个部分到了,自定义一个userString。
public class UserString : IConvertible, IUserDataType
{
private string userData = "";
public UserString(string data)
{
userData = data;
}
public TypeCode GetTypeCode()
{
return TypeCode.Object;
}
public string Trim()
{
return userData.Trim();
}
public string ToUpper()
{
return userData.ToUpper();
}
public string SubString(int startindex)
{
return userData.Substring(startindex);
}
public string SubString(int startindex, int length)
{
return userData.Substring(startindex, length);
}
public static bool operator ==(UserString value1, UserString value2)
{
return value1.userData == value2.userData;
}
public static bool operator !=(UserString value1, UserString value2)
{
return value1.userData != value2.userData;
}
public bool ToBoolean(IFormatProvider provider)
{
throw new Exception("The method or operation is not implemented.");
}
public byte ToByte(IFormatProvider provider)
{
throw new Exception("The method or operation is not implemented.");
}
public char ToChar(IFormatProvider provider)
{
throw new Exception("The method or operation is not implemented.");
}
public DateTime ToDateTime(IFormatProvider provider)
{
return Convert.ToDateTime(this.userData);
}
public decimal ToDecimal(IFormatProvider provider)
{
return Convert.ToDecimal(this.userData);
}
public double ToDouble(IFormatProvider provider)
{
throw new Exception("The method or operation is not implemented.");
}
public short ToInt16(IFormatProvider provider)
{
throw new Exception("The method or operation is not implemented.");
}
public int ToInt32(IFormatProvider provider)
{
return Convert.ToInt32(this.userData);
}
public long ToInt64(IFormatProvider provider)
{
throw new Exception("The method or operation is not implemented.");
}
public sbyte ToSByte(IFormatProvider provider)
{
throw new Exception("The method or operation is not implemented.");
}
public float ToSingle(IFormatProvider provider)
{
throw new Exception("The method or operation is not implemented.");
}
public string ToString(IFormatProvider provider)
{
return this.userData;
}
public object ToType(Type conversionType, IFormatProvider provider)
{
switch (Type.GetTypeCode(conversionType))
{
case TypeCode.Object:
if (conversionType.IsAssignableFrom(typeof(UserInt)))
return new UserInt(ToInt32(null));
else if (conversionType.IsAssignableFrom(typeof(UserDateTime)))
return new UserDateTime(ToDateTime(null));
else if (conversionType.IsAssignableFrom(typeof(UserDecimal)))
return new UserDecimal(ToDecimal(null));
else if (conversionType.IsAssignableFrom(typeof(UserString)))
return new UserString(ToString(null));
else
throw new InvalidCastException(String.Format("Conversion to a {0} is not supported.", conversionType.Name));
case TypeCode.Int32:
return ToInt32(null);
case TypeCode.Decimal:
return ToDecimal(null);
case TypeCode.DateTime:
return ToDateTime(null);
case TypeCode.String:
return ToString(null);
default:
throw new InvalidCastException(String.Format("Conversion to {0} is not supported.", conversionType.Name));
}
}
public ushort ToUInt16(IFormatProvider provider)
{
throw new Exception("The method or operation is not implemented.");
}
public uint ToUInt32(IFormatProvider provider)
{
throw new Exception("The method or operation is not implemented.");
}
public ulong ToUInt64(IFormatProvider provider)
{
throw new Exception("The method or operation is not implemented.");
}
public bool isGreater(IUserDataType obj1)
{
return false;
}
public bool isSmaller(IUserDataType obj1)
{
return false;
}
public bool isEqual(IUserDataType obj1)
{
if (!obj1.GetType().Equals(typeof(UserString))) return false;
return this == (obj1 as UserString);
}
public bool isUnEqual(IUserDataType obj1)
{
if (!obj1.GetType().Equals(typeof(UserString))) return false;
return this != (obj1 as UserString);
}
public bool isMoreOrEqual(IUserDataType obj1)
{
return false;
}
public bool isLessOrEqual(IUserDataType obj1)
{
return false;
}
}
userString类继承自两个接口,分别是IConvertible和IUserDataType。
userString重要的原因是ToType函数,因为IConvertible在convert.changeType函数中实现的函数就是ToType。如果你能看懂这个ToType函数,那么基本上自定义类型转换的核心内容就了解完毕了。
好了,下面再说说具体实现,具体实现我只说说我的思路,具体代码需要你自己实现。不过别担心,我已经实现过了,这个思路是没问题的。
例子:
输入为:"int","23",">","int","32",这是一个典型的int类型的比较大小的操作。
1.根据"int"来生成一个Type,使用函数UserDataType.getType。
2.根据"23","32",使用UserString来生成两个UserString类型的对象,使用构造函数生成。
3.利用Convert.changeType来讲两个userString对象转换成userInt类型,changetype函数的两个参数分别为object和type,那么两个传入的传输分别为userstring对象和userint的type。
4.对操作符号进行枚举,比如此例子中操作符号为">",那么对应的IUserDataType的函数为isGreater,调用之后返回了false。
PS:我的英文水平很差,所以在函数定义命名方面不是很准确,见谅。此文的出现是为了记录我之前所做过的事情,以免以后忘记。