Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Общие вопросы по .NET и C# > Unable to cast object of type...


Автор: SLeN 20.2.2010, 18:51
К примеру имеется простейший врапер для string

Код

    public class SimpleWrapper
    {
        string _value;
        public SimpleWrapper(string arg)
        {
            _value = arg;
        }

        public static explicit operator String(SimpleWrapper arg)
        {
            return arg._value;
        }
    }


Соответственно проходит на ура:

Код

        [Test]
        public void ExplicitCast()
        {
            SimpleWrapper wrapper = new SimpleWrapper("some string");
            Assert.AreEqual("some string", (string)wrapper);
        }


Но после упаковки в Object 

Код

        [Test]
        public void ExplictCastFromObject()
        {
            SimpleWrapper wrapper = new SimpleWrapper("some string");
            object obj = wrapper;
            Assert.AreEqual("some string", (string)obj);
        }


Вываливает Exception:

System.InvalidCastException : Unable to cast object of type 'SimpleWrapperCast.SimpleWrapper' to type 'System.String'

Как можно реализовать такую функциональность??? 

Автор: kobra 20.2.2010, 21:05
aа так?
Код
 Assert.AreEqual("some string", (string)(SimpleWrapper)obj);

Автор: SLeN 21.2.2010, 09:28
kobra, в таком случае клиентский код должен знать что он работает с врапером, чего не хотелось бы.

Автор: nmn 21.2.2010, 17:09
Цитата(SLeN @ 21.2.2010,  09:28)
kobra, в таком случае клиентский код должен знать что он работает с врапером, чего не хотелось бы.

попробуй заменить на implicit,
хотя это вряд ли поможет, в c# строгая типизация, тип содержащийся в object должнен соответствовать приводимому типу или быть его наследником

Автор: SLeN 21.2.2010, 19:51
nmn, implicit к сожалению не поможет, честно говоря я вобще ни вижу ни одного способа приведения из object, кроме как использовать прокси класс (на подобии NHibernate'овского), но тот же стринг - закрытый класс и такая штука не пройдет.

По тому и создал тему на форуме надеясь на русский авось  smile 

Автор: kobra 22.2.2010, 10:20
а как на счет рефлексии?

Автор: KelTron 22.2.2010, 13:13
Если нужен именно string, то можно просто переопределить ToString для твоего враппера.

Автор: SLeN 24.2.2010, 19:46
kobra, не уловил сути идеи


KelTron, нет в данном случае это не поможет, после упаковки в object вывалится тоже исключение

p.s.:

KelTron, тугодумлю вечером, ты предлагаешь в клиентском коде .ToString() использовать, а не приведение, но в данном случае опять таки клиентский код должен знать что работает с враппером - что не желательно.

Автор: KelTron 24.2.2010, 20:02
Я имел в виду:
Код

public class SimpleWrapper
{
    string _value;
    public SimpleWrapper(string arg)
    {
        _value = arg;
    }

    public override string ToString()
    {
        return _value;
    }
}

SimpleWrapper wrapper = new SimpleWrapper("some string");
object obj = wrapper;
Assert.AreEqual("some string", obj.ToString());

Но это только для строк...

Автор: SLeN 24.2.2010, 20:07
Именно этот вариант я и отметил в постскриптуме.

Автор: KelTron 24.2.2010, 20:22
Цитата(SLeN @  24.2.2010,  20:07 Найти цитируемый пост)
Именно этот вариант я и отметил в постскриптуме.

Ну когда я писал его ещё не было..)

Цитата(SLeN @  24.2.2010,  19:46 Найти цитируемый пост)
клиентский код должен знать что работает с враппером

Почему? Там нигде нет приведения к SimpleWrapper.

Автор: SLeN 24.2.2010, 20:30
По тому что от потребителя будет требоваться явно вызвать ToString()
К примеру если потребитель - NHibernate, он ToString() вызывать не будет, просто попытается привести к String.

Автор: KelTron 24.2.2010, 21:11
Единственный вариант реализации который я вижу:
Код

class A 
{
    public static explicit operator SomeType(A a)
    {
        return a.ConvertToSomeType();
    }

    protected virtual SomeType ConvertToSomeType()
    {
        return ...
    }
}

class B : A
{
    public static explicit operator SomeType(B b)
    {
        return b.ConvertToSomeType();
    }

    protected override SomeType ConvertToSomeType()
    {
        return ...
    }
}


A a1 = new A();
(SomeType)a1 // A.operator SomeType
A a2 = new B();
(SomeType)a2; // B.operator SomeType

Но это прокатило бы если бы ты мог изменить класс object, т.к. это невозможно, значит и такое поведение не реализовать...

Автор: mrbrooks 25.2.2010, 11:30
Цитата(SLeN @  21.2.2010,  19:51 Найти цитируемый пост)
но тот же стринг - закрытый класс и такая штука не пройдет.

если использовать расширения - это уже не проблема.

Автор: SLeN 25.2.2010, 12:34
mrbrooks, к сожалению расширения так же не решают поставленной задачи, клиентский код должен будет делать явные вызовы.

Я полагаю что задача не решаема.

Автор: Povter3092 25.2.2010, 13:11
Если, я правильно понимаю, что задача заключается в том, чтобы клиенту поставить обёртку в виде object, а клиент должен её преобразовать в тип, с которым эта обертка работает с помощью оператора явного преобразования. В этом случае можно добавить в обёртку следующий метод:

        public object ToObject()
        {
            return _value;
        }

тогда следующий код будет работать:

        public static void ExplictCastFromObject()
        {
            SimpleWrapper wrapper = new SimpleWrapper("some string");
            object obj = wrapper.ToObject();
            string str = (string)obj;
        }

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)