2014-10-15 2 views
1

В настоящее время у меня есть общий класс, который позволяет использовать выражение в качестве значения.неявное преобразование из T и строки

public class Expression<T> 
{ 
    public T Value { get; set; } 
    public string ExpressionText { get; set; } 

    public static implicit operator Expression<T>(string input) 
    { 
     if (string.IsNullOrEmpty(input)) 
      return null; 

     if (input.StartsWith("=")) 
      return new Expression<T> { ExpressionText = input }; 

     var converter = TypeDescriptor.GetConverter(typeof(T)); 
     T value = (T)converter.ConvertFromString(input); 

     return new Expression<T> { Value = value }; 
    } 

    public static implicit operator Expression<T>(T value) 
    { 
     if (value == null) 
      return null; 

     return new Expression<T> { Value = value }; 
    } 

То, что я хотел бы быть в состоянии сделать это, чтобы установить свойства, используя неявные преобразования из обоих Т и из строки. Однако, если выражение имеет строку типа, компилятор не может решить, какое преобразование использовать.

Есть ли умный способ обойти это?

Спасибо,

Шон

ответ

3

Вы не будете в состоянии держать обе неявные операторы и рассчитывать на работу с Expression<string> из-за better conversion rule

Учитывая неявное C1 преобразования, который преобразует из типа S к типу Т1 и неявное С2 преобразования, который преобразует из типа S к типа Т2, тем лучше преобразование двух преобразований определяется как следующим образом:

  • Если T1 и T2 одного типа, ни одно преобразование не лучше.
  • Если S является T1, C1 является лучшим преобразованием.
  • Если S является T2, C2 является лучшим преобразованием.
  • Если существует неявное преобразование из T1 в T2 и не существует никакого неявного преобразования из T2 в T1, C1 является лучшим преобразованием.
  • Если существует неявное преобразование из T2 в T1, и не существует никакого неявного преобразования из T1 в T2, C2 является лучшим преобразованием.
  • Если T1 является sbyte и T2 является байтом, ushort, uint или ulong, C1 является лучшим преобразованием.
  • Если T2 является sbyte и T1 является байтом, ushort, uint или ulong, C2 является лучшим преобразованием.
  • Если T1 короткий, а T2 - ushort, uint или ulong, C1 - лучшее преобразование.
  • Если T2 является коротким и T1 является ushort, uint или ulong, C2 является лучшим преобразованием.
  • Если T1 является int и T2 является uint, или ulong, C1 является лучшим преобразованием.
  • Если T2 является int и T1 является uint, или ulong, C2 является лучшим преобразованием.
  • Если T1 длинный, а T2 - улонг, C1 - лучшее преобразование.
  • Если T2 длинный, а T1 - улонг, C2 - лучшее преобразование.
  • В противном случае конвертация не лучше.

Если неявное преобразование С1 определяется этими правилами, чтобы быть лучше, чем преобразования неявного преобразования C2, то это также случай , что С2 является хуже, чем преобразование C1.

С Expression<string> вы явно в первом случае компилятор не будет выбирать для вас и будет just stop there.

Если не один член функции, которая лучше, чем все остальные члены функции, то вызов состоит функцию неоднозначных и возникает ошибка времени компиляции.

Таким образом, вы не сможете обрабатывать только операторы преобразования; либо создайте дополнительные методы для явной обработки строки, преобразуйте строку в T за пределами оператора или создайте абстракцию обертывания, которая сможет транпортировать T, строковое представление T или значение ExpressionText и преобразовать из него.

+1

Спасибо за подробный ответ. Я решил создать статический метод, который будет обрабатывать преобразование из строки и использовать неявное преобразование для T, поскольку это будет наиболее часто используемое из двух. – seanzi

1

Определение общего новообращенного и определенный тип преобразования вы на самом деле генерации неоднозначность. Но вам не нужно определять конкретный (строковый) конвертер, поскольку общий он уже охватывает все случаи.

public class Expression<T> 
{ 
    public T Value { get; set; } 
    public string ExpressionText { get; set; } 

    public static Expression<T> Convert(string input) 
    { 
     if (string.IsNullOrEmpty(input)) 
      return null; 

     if (input.StartsWith("=")) 
      return new Expression<T> { ExpressionText = input }; 

     var converter = TypeDescriptor.GetConverter(typeof(T)); 
     T value = (T)converter.ConvertFromString(input); 

     return new Expression<T> { Value = value }; 
    } 

    public static implicit operator Expression<T>(T value) 
    { 
     if (value == null) 
      return null; 

     var str = value as string; 
     if (!string.IsNullOrEmpty(str)) 
      return Convert(str); 
     else 
      return new Expression<T> { Value = value }; 
    } 
} 
+1

Ваш код просто возвращает нулевое значение, если 'value' не' string' – DarkWanderer

+0

@DarkWanderer Oh! да, спасибо, что указали это, я обновил его. – Shuping

1

попробуйте этот.

namespace ConsoleApplication11 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      Expression<string> str = "1"; 

     } 
    } 
    public class Expression<T> 
    { 
     public T Value { get; set; } 
     public string ExpressionText { get; set; } 



     public static implicit operator Expression<T>(T value) 
     { 
      if (value is string) { 
       string input = value.ToString(); 
       if (string.IsNullOrEmpty(input)) 
        return null; 

       if (input.StartsWith("=")) 
        return new Expression<T> { ExpressionText = input }; 

       var converter = TypeDescriptor.GetConverter(typeof(T)); 
       T tValu = (T)converter.ConvertFromString(input); 

       return new Expression<T> { Value = tValu }; 
      } 
      else if (value == null) 
       return null; 

      return new Expression<T> { Value = value }; 
     } 
    } 
} 
0

Ничто не мешает вам использовать проверку типа во время выполнения:

if (input is string) 
    return new Expression<T>(input as string); // delegate to explicit constructor 
Смежные вопросы