C #: Как я могу использовать неявный оператор приведения во время преобразования объекта в тип? - PullRequest
4 голосов
/ 18 марта 2009

HI!

Вот мой случай: у меня есть некоторый тип значения, который упакован в другой тип с соответствующими неявными конвертерами. Если я приведу обернутый тип к объекту, а затем попытаюсь получить исходное значение, я могу сделать это только в два этапа. Если упростить мой код выглядит следующим образом:

public enum MyEnum : int
    {
        First,
        Second
    }


    public class Test<T>
    {
        public Test(T val)
        {
            Value = val;
        }

        private T Value { get; set; }


        public static implicit operator T(Test<T> m)
        {
            return m.Value;
        }

        public static implicit operator Test<T>(T m)
        {
            var res = new Test<T>(m);
            return res;
        }
    }


    static void Main()
    {
        object res = new Test<MyEnum>(MyEnum.First);
        Console.WriteLine((MyEnum)(Test<MyEnum>)res);
        Console.WriteLine((MyEnum)res);
    }

Первый «Console.WriteLine» работает нормально. Второй сбой.

Есть ли способ изменить это поведение и заставить его работать без двойного приведения?

ОБНОВЛЕНИЕ 1

Я должен использовать объект для приведения значения (в реальном приложении мне нужно привести свойство ComboBox.SelectedItem, и я не хочу добавлять дополнительное свойство в ComboBox, потому что мне придется везде менять свой код взаимодействия с пользовательским интерфейсом).

ОБНОВЛЕНИЕ 2

Неявные преобразования в и из System.Object не допускаются.

ОБНОВЛЕНИЕ 3

Обновлен мой пример кода, чтобы отразить всю проблему.

Ответы [ 6 ]

6 голосов
/ 18 марта 2009

Не используйте object таким образом. Напишите свою первую строку следующим образом:

Test res = new Test(1);

Если вы сначала должны иметь его в объекте, помните, что все, что знает компилятор *1006*, на данный момент - это объект, и ничего более. У вас, как у программиста, есть дополнительная информация о том, что вы ожидаете от этого объекта, но для того, чтобы компилятор использовал эту информацию, вы должны поместить ее в свой код где-то.

Обновление:
Я рад, что смог найти это снова, потому что эта почти-очень своевременная статья Эрика Липперта, который работает над дизайном языка C #, вышла сегодня утром и подробно объясняет проблему:
http://blogs.msdn.com/ericlippert/archive/2009/03/19/representation-and-identity.aspx

4 голосов
/ 18 марта 2009

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

public static T To<T>(this object obj) {
    Type type = obj.GetType();
    MethodInfo[] methods = type.GetMethods(BindingFlags.Public | BindingFlags.Static);
    MethodInfo method = methods.FirstOrDefault(mi => (mi.Name == "op_Implicit" || mi.Name == "op_Explicit") && mi.ReturnType == typeof(T));
    if (method == null)
        throw new ArgumentException();
    return (T)method.Invoke(null, new[] { obj });
}

Использование

Console.WriteLine(res.To<MyEnum>());
2 голосов
/ 18 марта 2009

Вместо добавления неявных операторов рассмотрите реализацию IConvertible . Вам нужно только реализовать метод ToInt32, остальные не имеют смысла, и вы можете выбросить InvalidCastException в других методах.

После этого вы можете использовать метод Convert.ToInt32 () для преобразования вашего объекта за один шаг.

1 голос
/ 18 марта 2009

Ваша локальная переменная res всегда имеет тип object; поэтому строка, которая не работает, пытается преобразовать объект, который не является int, в int, чего нельзя сделать. То же, что и это не так:

        object d = 5.5d;
        Console.WriteLine((int)d);

EDIT:

Возможно, шаблон, который может помочь, выглядит примерно так:

        if (res.GetType() == typeof(Test))
        {
            Console.WriteLine((int)(Test)res);
        }
        else
        {
            Console.WriteLine((int)res);
        }

Это очень локализованное решение вашей проблемы, но, возможно, оно подойдет вам.

1 голос
/ 18 марта 2009

или даже

var res = new Test(1);
0 голосов
/ 18 марта 2009

Хотя ошибка связана с типом объекта res, я бы сделал оператор Test-> int явным ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...