Search code examples
c#typedescriptor

TypeDescriptor does not recongnise date


I'm having an ussue with the TypeDescriptor class.

I have a cookie which contains a date - the date is converted to a string and then back again using some helper methods.

One of my staple extension methods is used to do the conversion, however it throws a forced error because the date is not convertible back from a string.

Here's the message I output:

22/01/2015 14:29:15 could not be converted to DateTime

Looks like a DateTime to me!

The problem can be overcome by using Convert.ToDateTime(), so the code in general is ok. i also use it for dates elwhere with no problems to date.

The only difference is that I'm converting in the middle of a linq statement like this:

            Set = new SortedSet<TrackedItem>(set
                .Split(';')
                .Select(s =>
                {
                    var parts = s.Split(',');
                    return new TrackedItem(
                           parts[0].ConvertTo<int>(),
                           Convert.ToDateTime(parts[1]));
                }));

Any ideas?

    public static T ConvertTo<T>(this object obj, bool throwInvalid = false)
        where T : IConvertible
    {
        // Object does not require converting.
        if (obj is T) return (T)obj;

        // Determine if object can be converted. 
        var type = typeof(T);
        var converter = TypeDescriptor.GetConverter(type);

        var isConvertible = converter != null && converter.IsValid(obj);

        var error = string.Format("'{0}' could not be converted to type {1}", obj, type.Name);

        // If no conversion is available, and defaults not allowed throw an error. 
        (!isConvertible && throwInvalid).ThrowTrue(error);

        // If the object is convertible, convert it, else return the default(T).
        return isConvertible ? (T)converter.ConvertFrom(obj) : default(T);
    }

Solution

  • I'm guessing from your date example that you're running in the en-GB culture. Unfortunately, to draw liberally from this related q/a, IsValid always uses CultureInfo.InvariantCulture (US date format) to decide its answer. So when running in en-GB with a date such as your example, IsValid will return false; but ConvertFrom, which by default uses the current thread culture will succeed!

    Interestingly, the latest docs for IsValid massively hedge the question of whether this is actually a bug:

    The IsValid method is used to validate a value within the type rather than to determine if value can be converted to the given type. For example, IsValid can be used to determine if a given value is valid for an enumeration type.

    So really you shouldn't be using IsValid here at all - you should be doing what the same docs go on to suggest:

    You can write your own WillConvertSucceed method by wrapping the ConvertTo and ConvertFrom methods in exception blocks.

    And in that method you can be sure to use the CultureInfo you actually care about.