C#通过IConvertible接口来实现自定义类型转换和计算

来源:互联网 发布:linux项目经理招聘 编辑:程序博客网 时间:2024/06/06 05:41

如果有一个需求,用户输入数据类型和操作符号的字符串,你需要根据这些字符串来分析出用户想要的结果。

比如用户输入的是:"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:我的英文水平很差,所以在函数定义命名方面不是很准确,见谅。此文的出现是为了记录我之前所做过的事情,以免以后忘记。