3

在 C# 中,我处于环境提供的以下类型的场景中:

public interface IFoo {
}

public abstract class Base {
}

public class Derived : Base, IFoo {
}

public class Arbitrary {
    public Base GetBase() { }
}

这是我写的除此之外的内容。请注意,我可以保证在我的代码Arbitrary.GetBase()始终返回.Derived

public class Arbitrary2 : Arbitrary {
    public IFoo GetDerived() {
        return (IFoo)base.GetBase();
    }
}

但是,此代码失败并显示消息“无法将类型 'Base' 转换为 'IFoo'”。

但是,如果我这样做,那么它会起作用:

public class Arbitrary2 : Arbitrary {
    public IFoo GetDerived() {
        Object baseAsObject = base.GetBase();
        return (IFoo)baseAsObject ;
    }
}

为什么在我将它向下转换为 IFoo 之前必须向上转换为 Object?这两段代码在功能上是相同的,如果强制转换无效,后者会在运行时可靠地崩溃。我不明白为什么编译器会抱怨。

4

6 回答 6

6

你不需要这样做。您的代码应该可以正常工作。有关详细信息,请参阅此程序:

using System;

public interface IFoo { }

public abstract class Base { }

public class Derived : Base, IFoo { }

public class Arbitrary {
    public Base GetBase() { return new Derived(); }
}

public class Arbitrary2 : Arbitrary {
    public IFoo GetDerived() {
        return (IFoo)base.GetBase();
    }
}

class Program
{
    static void Main(string[] args)
    {
        Arbitrary2 test = new Arbitrary2();
        IFoo check = test.GetDerived();

        Console.WriteLine(check.GetType().Name);

        Console.WriteLine("Press key to exit:");
        Console.ReadKey();
    }
}
于 2012-07-11T18:25:24.437 回答
1

您的 GetBase() 方法返回 Base,它没有实现 IFoo。

于 2012-07-11T18:25:26.927 回答
1

Base无法转换为,IFoo因为与以下Base内容没有任何关系IFoo

public abstract class Base { }

根据此声明,很可能Base存在不属于 type 的实例IFoo。事实上,基于这个声明,编译器绝对没有理由假设任何给定的实例Base都会实现IFoo.

Derived实现IFoo

public class Derived : Base, IFoo { }

但你不是返回 a Derived,而是返回 a Base。通过对它进行多态化,Object您实际上是在“欺骗”编译器。你告诉它你知道的比它多,它应该听你的。这可以很好,只要您实际上比编译器知道的更多。你知道编译器不知道的是每个实例都Base可以多态为IFoo.

在那种情况下,为什么不直接实施IFooon Base?这样你就可以与编译器分享你的知识,每个人都会很高兴。

于 2012-07-11T18:27:54.107 回答
1

编译器不允许显式转换的原因是Base它没有实现IFoo.

如果您可以保证GetBase()始终返回 a Derived,那么您只需在演员Derived表之前插入IFoo演员表:

public class Arbitrary2 : Arbitrary {
    public IFoo GetDerived() {
        return (IFoo)(Derived)base.GetBase();
    }
}

当然,如果您弄错了,这将在运行时抛出。或者,您可以使用as强制转换将在null失败时返回:

public class Arbitrary2 : Arbitrary {
    public IFoo GetDerived() {
        return base.GetBase() as IFoo;
    }
}
于 2012-07-11T18:28:09.233 回答
1

Arbitrary.GetBase()返回 的实例BaseBase的层次结构不包含IFoo.

在运行时,是的,您的对象是一个Derived实例,但是基于编译器所知道的——类关系——没有连接,因此没有一种方法可以BaseIFoo您尝试使用第一种方法时进行转换。

于 2012-07-11T18:29:01.120 回答
1

你就不能写吗

public class Arbitrary2 : Arbitrary {
    public IFoo GetDerived() {
        return (Derived)this.GetBase();
    }
}

Derived编译器将看到and之间的连接Base,因此显式转换 toDerived应该是可以的。那么 anyDerived肯定是IFoo,所以不需要额外的时间(转换是隐式的)。

不要使用base.关键字。要么说this.(如上)要么省略。

编辑:另外,您的原始代码确实编译了,但我的版本可能更容易阅读。

于 2012-07-11T21:08:22.180 回答