Почему я получаю InvalidCastException здесь? - PullRequest
1 голос
/ 19 апреля 2019

У меня есть два следующих класса:

    public class Foo : IFooOperations
    {
        public FooData Data { get; set; }
        public FooUser User { get; set; }

        public Foo(FooData fooData)
        {
            Data = fooData;
        }

        private async void SetupFoo()
        {
            ...
        }

        public async void FooOp()
        {
            ...
        }
    }

и

    public class Bar : Foo, IBarOperations
    {

        public Foo(FooData fooData) : base(fooData)
        {
        }

        public async void BarOp()
        {
            ...
        }
    }

После того, как мне дали Foo объект, почему Bar bar = (Bar)foo; не позволяет мне привести его к Bar объекту? Вместо этого выдается исключение InvalidCastException: Specified cast is not valid..

По-моему, это должно сработать. Bar это просто Foo с одним дополнительным методом, работающим с состоянием, которое уже является общим для обоих объектов.

Некоторый дополнительный контекст: Bar объекты по существу являются привилегированными Foo пользователями, которым на основании их данных разрешен доступ к методу BarOp(). Я собираю SDK и хочу (ab) использовать механизм приведения, чтобы скрыть эти привилегированные методы по умолчанию. Я хочу, чтобы мой конечный пользователь должен был принять сознательное решение о том, что Foo действительно является Bar, и выполнить приведение, прежде чем он сможет получить доступ к методу BarOp().

У кого-нибудь есть идеи о том, что может быть не так, как я могу это исправить или какие альтернативные архитектуры следует рассмотреть?

1 Ответ

0 голосов
/ 19 апреля 2019

Bar - это просто Foo с единственным дополнительным методом, работающим с состоянием, которое уже является общим для обоих объектов.

Это совершенно неважно, будет ли работать каст. Приведение (между ссылочными типами, игнорируя определенные пользователем преобразования) может быть успешно выполнено в .NET, только если объект, на который ссылается , является экземпляром целевого типа или некоторого дочернего типа. Это так просто. Вы можете иметь два класса без любых дополнительных членов:

class Base {}
class Derived : Base {}

... и приведение все равно не удастся, если вы попытаетесь привести к Derived, когда у вас есть экземпляр Base:

Base b = new Base();
Derived d = (Derived) b; // Exception

Я хочу, чтобы мой конечный пользователь должен был принять осознанное решение о том, что Foo действительно является Bar, и выполнить приведение, прежде чем он сможет получить доступ к методу BarOp ().

Но объект не на самом деле Bar, в противном случае приведение будет работать. Ваш план был бы разумным, если бы вы гарантировали, что вы создали фактических Bar объектов в любое время.

Если вы не пытаетесь добавить какую-либо безопасность во время выполнения, просто заставьте разработчика сказать: «Я действительно хочу это сделать», тогда вы можете написать тип оболочки:

class Bar : IBarOperations
{
     // Keep a reference to the existing Foo object
     // Expose privileged methods         
}

Тогда, если вы хотите использовать свободный стиль, вы можете написать экземпляр или метод расширения для Foo из AsBar(), который создает новый Bar, что приводит к коду:

foo.AsBar().BarOp();

Это все еще поддерживает дополнительную «проверку» (даже при том, что это действительно не подтверждает, что пользователь должен быть в состоянии сделать это), не пытаясь использовать приведение.

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