简体   繁体   中英

Why am I receiving an InvalidCastException here?

I have the following two classes:

    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()
        {
            ...
        }
    }

and

    public class Bar : Foo, IBarOperations
    {

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

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

After I've been given a Foo object, why does Bar bar = (Bar)foo; not allow me to cast this to a Bar object? It throws an InvalidCastException: Specified cast is not valid. exception instead.

In my mind, this ought to work. Bar is just Foo with a single additional method operating on state which is already common to both objects.

Some additional context: the Bar objects are essentially privileged Foo users who, based on their data, are permitted to access the BarOp() method. I'm building an SDK and want to (ab)use the cast mechanism to hide these privileged methods by default. I want my end user to need to make the conscious decision that the Foo is indeed a Bar and perform the cast before they are able to access the BarOp() method.

Does anyone have any ideas about what might be wrong, how I might fix this, or alternative architectures to consider?

Bar is just Foo with a single additional method operating on state which is already common to both objects.

That's completely irrelevant to whether or not a cast will work. A cast (between reference types, ignoring user-defined conversions) can only succeed in .NET if the object that's referred to is an instance of the target type, or some child type. It's that simple. You could have two classes without any extra members:

class Base {}
class Derived : Base {}

... and a cast would still fail if you try to cast to Derived when you've actually got an instance of Base :

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

I want my end user to need to make the conscious decision that the Foo is indeed a Bar and perform the cast before they are able to access the BarOp() method.

But the object isn't actually a Bar , otherwise the cast would work. Your plan would be sound if you ensured that you created actual Bar objects any time you should.

If you're not trying to add any execution-time safety, just make the developer say "I really mean to do this" then you could write a wrapper type:

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

Then if you want to use a fluent style, you could write an instance or extension method for Foo of AsBar() which constructs a new Bar , leading to code of:

foo.AsBar().BarOp();

That still maintains the extra "check" (even though it's really not validation that the user should be able to do that) without trying to use casting.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM