为什么我在这里收到InvalidCastException?

时间:2019-04-19 05:57:29

标签: c# inheritance interface casting

我有以下两个课程:

    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 :(得分:0)

  

Bar只是Foo,仅在状态上操作了一个附加方法,这两个对象已经对它们通用。

这与强制转换是否起作用完全无关。如果引用的对象是目标类型或某个子类型的实例,则强制转换(在引用类型之间,忽略用户定义的转换)只能在.NET中成功。就这么简单。您可以有两个没有任何个额外成员的课程:

class Base {}
class Derived : Base {}

...并且如果您实际上拥有Derived的实例时尝试转换为Base,则转换仍将失败:

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

我希望我的最终用户需要有意识地确定Foo确实是Bar,并在能够访问BarOp()方法之前执行强制转换。

但是对象不是实际上是Bar,否则强制转换将起作用。如果确保在任何时候都创建了 actual Bar对象,那么您的计划将是正确的。

如果您不打算添加任何执行时安全性,只需让开发人员说“我真的是想这样做”,那么您可以编写包装类型:

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

然后,如果您想使用流利的样式,则可以为Foo中的AsBar()写一个实例或扩展方法,以构造一个新的Bar,从而得到以下代码:

foo.AsBar().BarOp();

这仍然保持了额外的“检查”(即使实际上并不能验证用户应该能够做到这一点),而无需尝试使用强制转换。