而不用担心例外一般类型转换 [英] General type conversion without risking Exceptions

查看:116
本文介绍了而不用担心例外一般类型转换的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的工作,可以采取许多不同的数据类型(任何实现IComparable的)的控制。

我需要能够在通过另一个变量来比较这些。

如果主要的数据类型是一个DateTime,而我通过一个字符串,我需要


  • 试图将字符串转换为一个DateTime执行日期比较。

  • 如果字符串不能转换为DateTime然后做一个字符串比较。

所以我需要尝试从任何类型的任何类型转换的通用方法。很容易,净为我们提供了<一个href=\"http://msdn.microsoft.com/en-us/library/system.componentmodel.typeconverter.aspx\">TypeConverter类。

现在,我可以工作要做,以确定是否字符串可以转换为DateTime最好是使用异常。如果ConvertFrom引发了异常,我知道我不能做的转换和必须做字符串比较。

以下是我得到了最好的:

 字符串theString =99/12/2009;
        日期时间theDate =新日期时间(2009,11,1);        IComparable的OBJ1 = theString为IComparable的;
        IComparable的OBJ2 = theDate为IComparable的;        尝试
        {
            的TypeConverter变换器= TypeDescriptor.GetConverter(obj2.GetType());
            如果(converter.CanConvertFrom(obj1.GetType()))
            {
                Console.WriteLine(obj2.CompareTo(converter.ConvertFrom(OBJ1)));
                Console.WriteLine(日期比);
            }
        }
        赶上(FormatException)
        {
            Console.WriteLine(obj1.ToString().CompareTo(obj2.ToString()));
            Console.WriteLine(字符串比较);
        }

我们的工作国家标准部分是:

例外只应提出当一个异常情况 - 即。遇到错误。

但是,这不是一个特殊的情况。我需要另一种方式解决它。

大多数变量类型有一个的TryParse 方法,该方法返回一个布尔值,让您以确定是否转换成功与否。但没有提供给TypeConverter的TryConvert方法。 <一href=\"http://msdn.microsoft.com/en-us/library/system.componentmodel.typeconverter.canconvertfrom.aspx\">CanConvertFrom只有当它是可能将这些类型之间的转换和犯规考虑要转换的实际数据dermines。该的IsValid 方法也没用了。

任何想法?

修改

我不能使用AS和IS。我不知道在编译时无论是数据类型。所以,我不知道该怎么当,并且是!!!

修改

好吧钉的私生子。它并不像整齐的马克Gravells,但它工作(我希望)。感谢您的inpiration马克。可工作于整理起来的时候,我得到的时间,但我已经得到了我一定要得到与错误修正的位堆栈。

 公共静态类CleanConverter
    {
        ///&LT;总结&gt;
        ///存储所有类型的可转换的所有类型的高速缓存。
        ///&LT; /总结&gt;
        私有静态字典&LT;类型,字典&LT;类型,ConversionCache&GT;&GT; _types =新词典&LT;类型,字典&LT;类型,ConversionCache&GT;&GT; ();        ///&LT;总结&gt;
        ///尝试解析。
        ///&LT; /总结&gt;
        ///&LT; PARAM NAME =S&GT;&LT; /参数&GT;
        ///&LT; PARAM NAME =值&GT;&LT; /参数&GT;
        ///&LT;&回报GT;&LT; /回报&GT;
        公共静态布尔的TryParse(IComparable的S,裁判IComparable的值)
        {
            //首先获得缓存转换方法。
            字典&LT;类型,ConversionCache&GT; type1Cache = NULL;
            ConversionCache type2Cache = NULL;            如果(!_Types.ContainsKey(s.GetType()))
            {
                type1Cache =新词典&LT;类型,ConversionCache&GT; ();                _Types.Add(s.GetType(),type1Cache);
            }
            其他
            {
                type1Cache = _types [s.GetType()];
            }            如果(!type1Cache.ContainsKey(value.GetType()))
            {
                //我们还没有转换成这种类型之前,因此创建一个新的转换
                type2Cache =新ConversionCache(s.GetType(),value.GetType());                //添加到高速缓存
                type1Cache.Add(value.GetType(),type2Cache);
            }
            其他
            {
                type2Cache = type1Cache [value.GetType()];
            }            //试图解析
            返回type2Cache.TryParse(S,参考值);
        }        ///&LT;总结&gt;
        ///门店的方法来转换类型1至2型
        ///&LT; /总结&gt;
        内部类ConversionCache
        {
            内部布尔的TryParse(IComparable的S,裁判IComparable的值)
            {
                如果(this._Method!= NULL)
                {
                    //调用缓存的TryParse方法。
                    [对象]参数=新的对​​象[] {S,值};
                    布尔结果=(布尔)this._Method.Invoke(NULL,参数);                    如果(结果)
                        值=参数[1] IComparable的;                    返回结果;
                }
                其他
                    返回false;            }            私人MethodInfo的_method;
            内部ConversionCache(类型1型,2型型)
            {
                //使用反射来从中获得的TryParse方法。
                this._Method = type2.GetMethod(的TryParse,新类型[] {TYPE1,type2.MakeByRefType()});
            }
        }
    }


解决方案

是仿制药的选项?下面是狩猎的的TryParse 方法,并通过(缓存)调用它代表面露黑客:

 使用系统;
使用的System.Reflection;静态类节目
{
    静态无效的主要()
    {
        INT I;浮F;十进制D组;
        如果(Test.TryParse(123,出一)){
            Console.WriteLine(ⅰ);
        }
        如果(Test.TryParse(123.45,走出F)){
            Console.WriteLine(F);
        }
        如果(Test.TryParse(123.4567,出D)){
            Console.WriteLine(四);
        }
    }
}
公共静态类测试
{
    公共静态布尔的TryParse&LT; T&GT;(字符串s,出的T值){
        返回高速缓存&LT; T&GT; .TryParse(S,超时值);
    }
    内部静态类缓存&LT; T&GT; {
        公共静态布尔的TryParse(字符串s,出的T值)
        {
            返回FUNC(S,超时值);
        }
        委托布尔TryPattern(字符串s,出的T值);
        私人静态只读TryPattern FUNC;
        静态缓存()
        {
            MethodInfo的方法= typeof运算(T).GetMethod(
                的TryParse,新类型[] {typeof运算(字符串)的typeof(T).MakeByRefType()});
            如果(方法== NULL){
                如果(typeof运算(T)== typeof运算(字符串))
                    FUNC =委托(字符串x,出牛逼Y){Y =(T)(对象)x;返回true; };
                其他
                    FUNC =委托(字符串x,出牛逼Y){Y =默认(T);返回false; };
            }其他{
                FUNC =(TryPattern)Delegate.CreateDelegate(typeof运算(TryPattern),法);
            }
        }
    }
}

I am working on a control that can take a number of different datatypes (anything that implements IComparable).

I need to be able to compare these with another variable passed in.

If the main datatype is a DateTime, and I am passed a String, I need to

  • attempt to convert the String to a DateTime to perform a Date comparison.
  • if the String cannot be converted to a DateTime then do a String comparison.

So I need a general way to attempt to convert from any type to any type. Easy enough, .Net provides us with the TypeConverter class.

Now, the best I can work out to do to determine if the String can be converted to a DateTime is to use exceptions. If the ConvertFrom raises an exception, I know I cant do the conversion and have to do the string comparison.

The following is the best I got :

        string theString = "99/12/2009";
        DateTime theDate = new DateTime ( 2009, 11, 1 );

        IComparable obj1 = theString as IComparable;
        IComparable obj2 = theDate as IComparable;

        try
        {
            TypeConverter converter = TypeDescriptor.GetConverter ( obj2.GetType () );
            if ( converter.CanConvertFrom ( obj1.GetType () ) )
            {
                Console.WriteLine ( obj2.CompareTo ( converter.ConvertFrom ( obj1 ) ) );
                Console.WriteLine ( "Date comparison" );
            }
        }
        catch ( FormatException )
        {
            Console.WriteLine ( obj1.ToString ().CompareTo ( obj2.ToString () ) );
            Console.WriteLine ( "String comparison" );
        }

Part of our standards at work state that :

Exceptions should only be raised when an Exception situation - ie. an error is encountered.

But this is not an exceptional situation. I need another way around it.

Most variable types have a TryParse method which returns a boolean to allow you to determine if the conversion has succeeded or not. But there is no TryConvert method available to TypeConverter. CanConvertFrom only dermines if it is possible to convert between these types and doesnt consider the actual data to be converted. The IsValid method is also useless.

Any ideas?

EDIT

I cannot use AS and IS. I do not know either data types at compile time. So I dont know what to As and Is to!!!

EDIT

Ok nailed the bastard. Its not as tidy as Marc Gravells, but it works (I hope). Thanks for the inpiration Marc. Will work on tidying it up when I get the time, but I've got a bit stack of bugfixes that I have to get on with.

    public static class CleanConverter
    {
        /// <summary>
        /// Stores the cache of all types that can be converted to all types.
        /// </summary>
        private static Dictionary<Type, Dictionary<Type, ConversionCache>> _Types = new Dictionary<Type, Dictionary<Type, ConversionCache>> ();

        /// <summary>
        /// Try parsing.
        /// </summary>
        /// <param name="s"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public static bool TryParse ( IComparable s, ref IComparable value )
        {
            // First get the cached conversion method.
            Dictionary<Type, ConversionCache> type1Cache = null;
            ConversionCache type2Cache = null;

            if ( !_Types.ContainsKey ( s.GetType () ) )
            {
                type1Cache = new Dictionary<Type, ConversionCache> ();

                _Types.Add ( s.GetType (), type1Cache );
            }
            else
            {
                type1Cache = _Types[s.GetType ()];
            }

            if ( !type1Cache.ContainsKey ( value.GetType () ) )
            {
                // We havent converted this type before, so create a new conversion
                type2Cache = new ConversionCache ( s.GetType (), value.GetType () );

                // Add to the cache
                type1Cache.Add ( value.GetType (), type2Cache );
            }
            else
            {
                type2Cache = type1Cache[value.GetType ()];
            }

            // Attempt the parse
            return type2Cache.TryParse ( s, ref value );
        }

        /// <summary>
        /// Stores the method to convert from Type1 to Type2
        /// </summary>
        internal class ConversionCache
        {
            internal bool TryParse ( IComparable s, ref IComparable value )
            {
                if ( this._Method != null )
                {
                    // Invoke the cached TryParse method.
                    object[] parameters = new object[] { s, value };
                    bool result = (bool)this._Method.Invoke ( null,  parameters);

                    if ( result )
                        value = parameters[1] as IComparable;

                    return result;
                }
                else
                    return false;

            }

            private MethodInfo _Method;
            internal ConversionCache ( Type type1, Type type2 )
            {
                // Use reflection to get the TryParse method from it.
                this._Method = type2.GetMethod ( "TryParse", new Type[] { type1, type2.MakeByRefType () } );
            }
        }
    }

解决方案

Are generics an option? Here's a cheeky hack that hunts the TryParse method and calls it via a (cached) delegate:

using System;
using System.Reflection;

static class Program
{
    static void Main()
    {
        int i; float f; decimal d;
        if (Test.TryParse("123", out i)) {
            Console.WriteLine(i);
        }
        if (Test.TryParse("123.45", out f)) {
            Console.WriteLine(f);
        }
        if (Test.TryParse("123.4567", out d)) {
            Console.WriteLine(d);
        }
    }
}
public static class Test
{
    public static bool TryParse<T>(string s, out T value) {
        return Cache<T>.TryParse(s, out value);
    }
    internal static class Cache<T> {
        public static bool TryParse(string s, out T value)
        {
            return func(s, out value);
        }    
        delegate bool TryPattern(string s, out T value);
        private static readonly TryPattern func;
        static Cache()
        {
            MethodInfo method = typeof(T).GetMethod(
                "TryParse", new Type[] { typeof(string), typeof(T).MakeByRefType() });
            if (method == null) {
                if (typeof(T) == typeof(string))
                    func = delegate(string x, out T y) { y = (T)(object)x; return true; };
                else
                    func = delegate(string x, out T y) { y = default(T); return false; };
            } else {
                func = (TryPattern) Delegate.CreateDelegate(typeof(TryPattern),method);
            }            
        }
    }
}

这篇关于而不用担心例外一般类型转换的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆