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

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

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

你可能感兴趣的:(学习笔录)