2013-05-30 3 views
3

Кажется, что TypeConverter.IsValid() использует текущую культуру темы, но TypeConverter.ConvertFrom() нет.TypeConverter.IsValid() использует текущую культуру потока, но TypeConverter.ConvertFrom() нет?

Это делает бесполезным использование TypeConverter.IsValid() с типом DateTime, если вы не находитесь в культуре инвариантов. Действительно, это кажется ошибкой.

Кто-нибудь знает, как сделать TypeConverter.IsValid() использовать текущую культуру?

Следующий код демонстрирует проблему.

Он использует две строки: одну в формате DD/MM/YYYY и одну в формате MM/DD/YYYY.

Первая часть теста проводится в Инвариантной культуре. Он демонстрирует, что TypeConverter.IsValid() возвращает true для строки MM/DD/YYYY, и вы можете использовать TypeConverter.ConvertFrom() для преобразования этой строки в DateTime.

В первой части также показано, что TypeConverter.IsValid() возвращает false для строки DD/MM/YYYY.

Для второй части я изменяю текущую культуру «en-GB», которая использует даты «DD/MM/YYYY».

Я бы ожидал, что результаты IsValid() будут отменены, но они вернутся так же, как и раньше, для двух строк. Поэтому он говорит, что строка MM/DD/YYYY действительна.

Однако - и это важный бит - если вы попытаетесь использовать TypeConverter.ConvertFrom(), чтобы фактически преобразовать строку, которую TypeConverter.IsValid() сказал (а): ok, вы получите исключение.

Есть ли способ обойти это?

using System; 
using System.ComponentModel; 
using System.Globalization; 
using System.Threading; 

namespace Demo 
{ 
    class Program 
    { 
     void Run() 
     { 
      // Start off with the US culture, which has MM/DD/YYYY date format. 

      Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; 

      var dateConverter = TypeDescriptor.GetConverter(typeof(DateTime)); 
      var goodDateString = "07/19/1961"; 
      var badDateString = "19/07/1961"; 

      test(dateConverter, goodDateString, "DateTime"); // Says it's good. 
      test(dateConverter, badDateString, "DateTime"); // Says it's bad. 

      var dateTimeValue = (DateTime) dateConverter.ConvertFrom(goodDateString); 

      Console.WriteLine("dateTimeValue = " + dateTimeValue); 
      Console.WriteLine(); 

      // Now lets change the current culture to the UK, which has DD/MM/YYYY date format. 

      Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("en-GB"); 
      dateConverter = TypeDescriptor.GetConverter(typeof(DateTime)); 

      test(dateConverter, goodDateString, "DateTime"); // Still says it's good. 
      test(dateConverter, badDateString, "DateTime"); // Still says it's bad. 

      // TypeConverter.IsValid(badDateString) returns false, so we shouldn't be able to convert it. 
      // Well, we can, like so: 

      dateTimeValue = (DateTime)dateConverter.ConvertFrom(badDateString); // Shouldn't work according to "IsValid()" 
      Console.WriteLine("dateTimeValue (bad) = " + dateTimeValue);  // But this is printed ok. 

      // TypeConverter.IsValid(goodDateString) returns true, so we can convert it right? 
      // Well, no. This now throws an exception, even though "IsValid()" returned true for the same string. 

      dateTimeValue = (DateTime)dateConverter.ConvertFrom(goodDateString); // This throws an exception. 
     } 

     void test(TypeConverter converter, string text, string type) 
     { 
      if (converter.IsValid(text)) 
       Console.WriteLine("\"" + text + "\" IS a valid " + type); 
      else 
       Console.WriteLine("\"" + text + "\" is NOT a valid " + type); 
     } 

     static void Main() 
     { 
      new Program().Run(); 
     } 
    } 
} 
+2

Из памяти «нет» прыгает на ум. Но я, кажется, помню, что существует целый ряд проблем с API-интерфейсом IsValid, и во всех случаях он не очень хорошо работает. Может потребоваться просто попробовать конвертировать и посмотреть, работает ли он. –

+0

@MarcGravell Aye, это похоже на подходящее действие - просто не используйте 'IsValid()' вообще. –

ответ

4

Это дефект в TypeConverter.IsValid(). Преобразователь типов поддерживает культуру, его виртуальный метод ConvertFrom() принимает аргумент CultureInfo. Вы используете не виртуальную перегрузку, которая не принимает CultureInfo, поэтому вы получите преобразование, выбранное CultureInfo.CurrentCulture.

TypeConverter.IsValid() делает не имеет перегрузку, которая принимает значение CultureInfo. И flubs CultureInfo он переходит к методу TypeConverter.ConvertFrom(), он передает CultureInfo.InvariantCulture.

Трудно найти оправдание такого поведения. Вероятно, ошибка, которую только что заметили, слишком поздно, чтобы что-то сделать. Это, безусловно, не исправляется.

Обходным путем является то, что делает IsValid(), но указав правильную культуру. Сначала вызовите CanConvertFrom(), затем вызовите ConvertFrom() в блок try/catch.

+0

Ах спасибо. Вы также ожидали другого вопроса, который у меня был бы: * '« Это менее эффективные ошибки catch с использованием исключений по сравнению с использованием IsValid()? »' * - но, к счастью, теперь я знаю, что это не имеет никакого значения. –

Смежные вопросы