неявное преобразование из T и строки

1

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

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 };
    }

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

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

Благодаря,

Шон

Теги:
implicit-conversion

4 ответа

3
Лучший ответ

Вы не сможете хранить оба неявных оператора и ожидать работы с Expression<string> из-за лучшего правила преобразования

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

  • Если 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 - лучшее преобразование.
  • В противном случае конвертация не будет лучше.

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

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

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

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

  • 1
    Спасибо за подробный ответ. Я решил создать статический метод, который будет обрабатывать преобразование из строки и использовать неявное преобразование для T, так как это будет наиболее часто используемый из двух.
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
  • 0
    @ DarkWanderer Ой! да, спасибо за указание на это, я обновил его.
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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню